Skip to content

Functions emulator file watcher silently ignores changes in git worktrees #10187

@khevamann

Description

@khevamann

[REQUIRED] Environment info

firebase-tools: 15.9.0

Platform: macOS (Darwin 25.2.0)

[REQUIRED] Test case

The Functions emulator's chokidar file watcher is configured with a regex to ignore hidden (dot-prefixed) directories:

// lib/emulator/functionsEmulator.js — line ~270
const watcher = chokidar.watch(backend.functionsDir, {
    ignored: [
        /.+?[\\\/]node_modules[\\\/].+?/,
        /(^|[\/\\])\../,   // <-- matches .worktrees in absolute path
        /.+\.log/,
        /.+?[\\\/]venv[\\\/].+?/,
        ...(backend.ignore?.map((i) => `**/${i}`) ?? []),
    ],
    persistent: true,
});

Chokidar tests this regex against absolute file paths. When the project is in a git worktree, every path contains /.worktrees/, which matches /(^|[\/\\])\../ at the /.w position:

/Users/dev/project/.worktrees/my-feature/functions/lib/index.js
                   ^^^^^^^^^^
                   matches /(^|[\/\\])\../

This causes every file change event to be silently dropped.

[REQUIRED] Steps to reproduce

  1. Create a git worktree: git worktree add .worktrees/my-feature
  2. cd .worktrees/my-feature
  3. Start the Functions emulator
  4. Observe the emulator logs — you should see Watching "<path>" for Cloud Functions... confirming the watcher is set up
  5. Edit a function source file and save
  6. Observe that the emulator never reloads — no Loaded functions definitions from source message appears

[REQUIRED] Expected behavior

The Functions emulator should detect file changes in the functions source directory and reload triggers, regardless of whether the project is inside a git worktree (.worktrees/) directory. After saving a file change, the emulator should log Loaded functions definitions from source: ... and serve the updated code.

[REQUIRED] Actual behavior

All file change events are silently ignored by chokidar because the absolute path contains /.worktrees/, which matches the hidden directory regex /(^|[\/\\])\../. The emulator continues serving stale code with no error or warning. The change event listener and loadTriggers reload mechanism work correctly — the issue is purely that the ignored regex prevents chokidar from ever firing events.

This can be confirmed in a Node REPL:

const re = /(^|[\/\\])\../;
re.test("/Users/dev/project/.worktrees/feature/functions/lib/index.js");
// → true (matched "/.w" in "/.worktrees")

Suggested Fix

Add a negative lookahead to exclude .worktrees from the hidden directory pattern:

// Before:
/(^|[\/\\])\../

// After:
/(^|[\/\\])\.(?!worktrees[\/\\])/

This preserves the intent of ignoring hidden directories (.git, .cache, etc.) while allowing git worktree paths to function correctly.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions