firebase / firebase/firebase-tools
Functions emulator file watcher silently ignores changes in git worktrees
- 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
Assessment
This issue has not been assessed yet.