You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: extensions/EXTENSION-DEVELOPMENT-GUIDE.md
+61Lines changed: 61 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -332,6 +332,67 @@ echo "$config"
332
332
333
333
---
334
334
335
+
## Excluding Files with `.extensionignore`
336
+
337
+
Extension authors can create a `.extensionignore` file in the extension root to exclude files and folders from being copied when a user installs the extension with `specify extension add`. This is useful for keeping development-only files (tests, CI configs, docs source, etc.) out of the installed copy.
338
+
339
+
### Format
340
+
341
+
The file uses `.gitignore`-compatible patterns (one per line), powered by the [`pathspec`](https://pypi.org/project/pathspec/) library:
342
+
343
+
- Blank lines are ignored
344
+
- Lines starting with `#` are comments
345
+
- `*`matches anything **except** `/` (does not cross directory boundaries)
346
+
- `**`matches zero or more directories (e.g., `docs/**/*.draft.md`)
347
+
- `?`matches any single character except `/`
348
+
- A trailing `/` restricts a pattern to directories only
349
+
- Patterns containing `/` (other than a trailing slash) are anchored to the extension root
350
+
- Patterns without `/` match at any depth in the tree
351
+
- `!`negates a previously excluded pattern (re-includes a file)
352
+
- Backslashes in patterns are normalised to forward slashes for cross-platform compatibility
353
+
- The `.extensionignore` file itself is always excluded automatically
354
+
355
+
### Example
356
+
357
+
```gitignore
358
+
# .extensionignore
359
+
360
+
# Development files
361
+
tests/
362
+
.github/
363
+
.gitignore
364
+
365
+
# Build artifacts
366
+
__pycache__/
367
+
*.pyc
368
+
dist/
369
+
370
+
# Documentation source (keep only the built README)
371
+
docs/
372
+
CONTRIBUTING.md
373
+
```
374
+
375
+
### Pattern Matching
376
+
377
+
| Pattern | Matches | Does NOT match |
378
+
|---------|---------|----------------|
379
+
| `*.pyc` | Any `.pyc` file in any directory | — |
380
+
| `tests/` | The `tests` directory (and all its contents) | A file named `tests` |
The following `.gitignore` features are **not applicable** in this context:
389
+
390
+
- **Multiple `.extensionignore` files**: Only a single file at the extension root is supported (`.gitignore` supports files in subdirectories)
391
+
- **`$GIT_DIR/info/exclude` and `core.excludesFile`**: These are Git-specific and have no equivalent here
392
+
- **Negation inside excluded directories**: Because file copying uses `shutil.copytree`, excluding a directory prevents recursion into it entirely. A negation pattern cannot re-include a file inside a directory that was itself excluded. For example, the combination `tests/` followed by `!tests/important.py` will **not** preserve `tests/important.py` — the `tests/` directory is skipped at the root level and its contents are never evaluated. To work around this, exclude the directory's contents individually instead of the directory itself (e.g., `tests/*.pyc` and `tests/.cache/` rather than `tests/`).
0 commit comments