Skip to content

[Critical Bug] findGitRoot() causes catastrophic data loss when parent directory contains .git #198

@a88883284

Description

@a88883284

What Happened

I lost 3,711 files in my home directory because evolver executed git reset --hard in the wrong directory.

My Setup

  • Evolver installed at: ~/.openclaw/workspace/skills/evolver/ (as a skill in OpenClaw workspace)
  • Parent directory ~/.openclaw/ had a .git folder (created unintentionally at some point)
  • Evolver running in loop mode via cron

The Bug

In src/gep/paths.js, the findGitRoot() function walks up the directory tree and returns the first .git it finds:

function findGitRoot(startDir) {
  let dir = startDir;
  while (dir && dir !== path.dirname(dir)) {
    const gitDir = path.join(dir, '.git');
    if (fs.existsSync(gitDir)) {
      return dir;  // Returns parent's .git, not evolver's own!
    }
    dir = path.dirname(dir);
  }
}

When evolution failed and triggered rollback, git reset --hard was executed in ~/.openclaw/ instead of ~/.openclaw/workspace/skills/evolver/.

Result: Everything in my home directory that wasn't committed to git was destroyed - including credentials, configurations, agent sessions, memory databases, and custom skills.

Root Cause

The function assumes that if a parent directory has .git, it's an intentional nested installation. But users often have .git folders in parent directories for various reasons:

  • Accidental git init
  • The parent is itself a project
  • Previous installations left behind

There's no safeguard to ensure evolver only operates within its own directory.

Proposed Fix

Modify findGitRoot() to only use evolver's own .git, and require explicit opt-in for parent git repos:

function findGitRoot(startDir) {
  let dir = startDir;
  let foundGitRoot = null;
  
  while (dir && dir !== path.dirname(dir)) {
    const gitDir = path.join(dir, '.git');
    if (fs.existsSync(gitDir)) {
      foundGitRoot = dir;
      break;
    }
    dir = path.dirname(dir);
  }
  
  // Safety: Only use parent's git if explicitly allowed
  if (foundGitRoot && foundGitRoot !== startDir) {
    if (process.env.EVOLVER_USE_PARENT_GIT === 'true') {
      console.warn('[Evolver] Using parent git repository at:', foundGitRoot);
      return foundGitRoot;
    }
    // Default: Use evolver's own directory, even if no .git exists
    console.warn('[Evolver] Parent directory has .git but EVOLVER_USE_PARENT_GIT is not set. Using evolver directory.');
    return startDir;
  }
  
  return foundGitRoot || startDir;
}

This ensures:

  1. Evolver defaults to its own directory (safe)
  2. Parent git repos require explicit opt-in via environment variable
  3. Users are warned when a parent .git is detected but ignored

Impact

This is a data loss bug that can affect anyone who:

  • Installs evolver as a subdirectory in an existing project
  • Has a .git folder anywhere in the parent directory chain

The current behavior is dangerous and should be fixed before more users lose their data.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions