Design: Git Worktree Support #180

Closed
opened 2026-01-24 10:31:04 +00:00 by jack · 0 comments
Owner

Hintergrund

Git Worktrees erlauben mehrere Working Directories für dasselbe Repository:

# Haupt-Repository
/home/user/repos/myproject (main branch)

# Worktrees
/home/user/repos/myproject-feature-a (feature-a branch)
/home/user/repos/myproject-hotfix (hotfix branch)

Alle drei Verzeichnisse gehören zum selben Repository, haben aber unterschiedliche Pfade.

Aktuelle Probleme

1. Project-Identifikation basiert auf Pfad

// Aktuell: Pfad = Projekt
project: params.workingDirectory

Bei Worktrees würden drei separate "Projekte" erstellt, obwohl es dasselbe Repository ist.

2. CLAUDE.md pro Verzeichnis

Jeder Worktree hätte seine eigene CLAUDE.md - Wissen wird nicht geteilt.

3. Observations sind pfadgebunden

Observations haben cwd als Pfad, nicht als Repository-Referenz.

Lösungsansatz

1. Repository-Erkennung

Git speichert Worktree-Info in .git:

# In einem Worktree ist .git eine Datei, keine Directory:
cat /path/to/worktree/.git
# gitdir: /home/user/repos/myproject/.git/worktrees/feature-a

# Haupt-Repository finden:
git rev-parse --git-common-dir
# /home/user/repos/myproject/.git

Implementierung:

import { execSync } from 'child_process';

interface RepoInfo {
  /** Canonical repository path (main worktree) */
  repoPath: string;
  /** Current worktree path */
  worktreePath: string;
  /** Whether this is a worktree (not main) */
  isWorktree: boolean;
  /** Current branch */
  branch: string;
}

function getRepoInfo(cwd: string): RepoInfo | null {
  try {
    // Get the common git dir (same for all worktrees)
    const gitCommonDir = execSync('git rev-parse --git-common-dir', { cwd })
      .toString().trim();
    
    // Get the main worktree path
    const repoPath = execSync('git worktree list --porcelain | head -1', { cwd })
      .toString().replace('worktree ', '').trim();
    
    // Check if current is a worktree
    const isWorktree = cwd !== repoPath;
    
    const branch = execSync('git branch --show-current', { cwd })
      .toString().trim();
    
    return { repoPath, worktreePath: cwd, isWorktree, branch };
  } catch {
    return null;
  }
}

2. Projekt-Identifikation ändern

Statt workingDirectory als Projekt-ID:

// Option A: Haupt-Repository-Pfad als Projekt
project: repoInfo?.repoPath ?? workingDirectory

// Option B: Repository-URL/Name als Projekt
project: getRemoteOrigin(workingDirectory) ?? workingDirectory

// Option C: Kombiniert
project: `${repoName}` // z.B. "claude-mem"
projectVariant: `${branch}` // z.B. "feature-a"

3. CLAUDE.md Strategie

Option A: Nur im Haupt-Repository

  • CLAUDE.md wird nur in repoPath geschrieben
  • Alle Worktrees teilen dieselbe Datei (problematisch bei unterschiedlichen Branches)

Option B: Pro Worktree, aber geteiltes Wissen

  • Jeder Worktree hat eigene CLAUDE.md
  • Observations werden mit repoPath verknüpft
  • Bei CLAUDE.md-Generierung: Observations aus allen Worktrees berücksichtigen

Option C: Branch-basierte Trennung

  • CLAUDE.md enthält Branch-spezifische Sections
  • Oder: Subdirectory .claude-mem/branches/feature-a.md

4. Datenbank-Schema Erweiterung

-- Sessions
ALTER TABLE sdk_sessions ADD COLUMN repo_path TEXT;
ALTER TABLE sdk_sessions ADD COLUMN is_worktree BOOLEAN DEFAULT FALSE;

-- Observations
ALTER TABLE observations ADD COLUMN repo_path TEXT;
ALTER TABLE observations ADD COLUMN branch TEXT;

-- Neue Tabelle für Repository-Tracking
CREATE TABLE repositories (
  id INTEGER PRIMARY KEY,
  repo_path TEXT UNIQUE NOT NULL,
  remote_url TEXT,
  name TEXT,
  created_at INTEGER
);

5. UI-Anpassungen

  • Projekt-Filter sollte Repository-basiert sein
  • Worktrees als "Varianten" eines Projekts anzeigen
  • Branch-Info in Session-Liste

Offene Fragen

  1. Wie mit lokalen Repos ohne Remote umgehen?

    • Fallback auf Pfad-basierte Identifikation?
  2. Was passiert wenn Worktree gelöscht wird?

    • Observations bleiben erhalten (repo_path existiert noch)
  3. Konflikt-Handling bei CLAUDE.md?

    • Wenn zwei Worktrees gleichzeitig aktiv sind
  4. Performance-Impact?

    • Git-Commands bei jedem Hook-Call?
    • Caching der Repo-Info pro Session?

Implementierungs-Reihenfolge

  1. getRepoInfo() Utility implementieren
  2. Session-Start: Repo-Info erfassen und speichern
  3. Projekt-Gruppierung in UI anpassen
  4. CLAUDE.md Generierung für Worktrees optimieren
  5. Migration für bestehende Daten

Betroffene Dateien

  • packages/hooks/src/handlers/session-start.ts
  • packages/backend/src/services/session-service.ts
  • packages/database/src/mikro-orm/entities/
  • packages/ui/src/views/ (Projekt-Filter)
  • Neue Utility: packages/shared/src/git-utils.ts

Priorität

Niedrig-Mittel - Nice-to-have für Power-User mit komplexen Workflows

## Hintergrund Git Worktrees erlauben mehrere Working Directories für dasselbe Repository: ```bash # Haupt-Repository /home/user/repos/myproject (main branch) # Worktrees /home/user/repos/myproject-feature-a (feature-a branch) /home/user/repos/myproject-hotfix (hotfix branch) ``` Alle drei Verzeichnisse gehören zum selben Repository, haben aber unterschiedliche Pfade. ## Aktuelle Probleme ### 1. Project-Identifikation basiert auf Pfad ```typescript // Aktuell: Pfad = Projekt project: params.workingDirectory ``` Bei Worktrees würden drei separate "Projekte" erstellt, obwohl es dasselbe Repository ist. ### 2. CLAUDE.md pro Verzeichnis Jeder Worktree hätte seine eigene CLAUDE.md - Wissen wird nicht geteilt. ### 3. Observations sind pfadgebunden Observations haben `cwd` als Pfad, nicht als Repository-Referenz. ## Lösungsansatz ### 1. Repository-Erkennung Git speichert Worktree-Info in `.git`: ```bash # In einem Worktree ist .git eine Datei, keine Directory: cat /path/to/worktree/.git # gitdir: /home/user/repos/myproject/.git/worktrees/feature-a # Haupt-Repository finden: git rev-parse --git-common-dir # /home/user/repos/myproject/.git ``` **Implementierung:** ```typescript import { execSync } from 'child_process'; interface RepoInfo { /** Canonical repository path (main worktree) */ repoPath: string; /** Current worktree path */ worktreePath: string; /** Whether this is a worktree (not main) */ isWorktree: boolean; /** Current branch */ branch: string; } function getRepoInfo(cwd: string): RepoInfo | null { try { // Get the common git dir (same for all worktrees) const gitCommonDir = execSync('git rev-parse --git-common-dir', { cwd }) .toString().trim(); // Get the main worktree path const repoPath = execSync('git worktree list --porcelain | head -1', { cwd }) .toString().replace('worktree ', '').trim(); // Check if current is a worktree const isWorktree = cwd !== repoPath; const branch = execSync('git branch --show-current', { cwd }) .toString().trim(); return { repoPath, worktreePath: cwd, isWorktree, branch }; } catch { return null; } } ``` ### 2. Projekt-Identifikation ändern Statt `workingDirectory` als Projekt-ID: ```typescript // Option A: Haupt-Repository-Pfad als Projekt project: repoInfo?.repoPath ?? workingDirectory // Option B: Repository-URL/Name als Projekt project: getRemoteOrigin(workingDirectory) ?? workingDirectory // Option C: Kombiniert project: `${repoName}` // z.B. "claude-mem" projectVariant: `${branch}` // z.B. "feature-a" ``` ### 3. CLAUDE.md Strategie **Option A: Nur im Haupt-Repository** - CLAUDE.md wird nur in `repoPath` geschrieben - Alle Worktrees teilen dieselbe Datei (problematisch bei unterschiedlichen Branches) **Option B: Pro Worktree, aber geteiltes Wissen** - Jeder Worktree hat eigene CLAUDE.md - Observations werden mit `repoPath` verknüpft - Bei CLAUDE.md-Generierung: Observations aus allen Worktrees berücksichtigen **Option C: Branch-basierte Trennung** - CLAUDE.md enthält Branch-spezifische Sections - Oder: Subdirectory `.claude-mem/branches/feature-a.md` ### 4. Datenbank-Schema Erweiterung ```sql -- Sessions ALTER TABLE sdk_sessions ADD COLUMN repo_path TEXT; ALTER TABLE sdk_sessions ADD COLUMN is_worktree BOOLEAN DEFAULT FALSE; -- Observations ALTER TABLE observations ADD COLUMN repo_path TEXT; ALTER TABLE observations ADD COLUMN branch TEXT; -- Neue Tabelle für Repository-Tracking CREATE TABLE repositories ( id INTEGER PRIMARY KEY, repo_path TEXT UNIQUE NOT NULL, remote_url TEXT, name TEXT, created_at INTEGER ); ``` ### 5. UI-Anpassungen - Projekt-Filter sollte Repository-basiert sein - Worktrees als "Varianten" eines Projekts anzeigen - Branch-Info in Session-Liste ## Offene Fragen 1. **Wie mit lokalen Repos ohne Remote umgehen?** - Fallback auf Pfad-basierte Identifikation? 2. **Was passiert wenn Worktree gelöscht wird?** - Observations bleiben erhalten (repo_path existiert noch) 3. **Konflikt-Handling bei CLAUDE.md?** - Wenn zwei Worktrees gleichzeitig aktiv sind 4. **Performance-Impact?** - Git-Commands bei jedem Hook-Call? - Caching der Repo-Info pro Session? ## Implementierungs-Reihenfolge 1. `getRepoInfo()` Utility implementieren 2. Session-Start: Repo-Info erfassen und speichern 3. Projekt-Gruppierung in UI anpassen 4. CLAUDE.md Generierung für Worktrees optimieren 5. Migration für bestehende Daten ## Betroffene Dateien - `packages/hooks/src/handlers/session-start.ts` - `packages/backend/src/services/session-service.ts` - `packages/database/src/mikro-orm/entities/` - `packages/ui/src/views/` (Projekt-Filter) - Neue Utility: `packages/shared/src/git-utils.ts` ## Priorität Niedrig-Mittel - Nice-to-have für Power-User mit komplexen Workflows
jack closed this issue 2026-01-24 17:20:38 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
customable/claude-mem#180
No description provided.