firebase / firebase/firebase-tools

Functions emulator file watcher silently ignores changes in git worktrees

Open
#10,187 2 comments 0 reactions 0 assignees View on GitHub
emulators: functions
Dominant language
TypeScript
Stars
4.5k
Forks
1.3k
Avg merge
1d 12h
Merged PRs (30d)
84

Description

### [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:

```js
// 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 "" 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:
```js
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:

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

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

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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.