feat: add adopt command to move existing files into the overlay - #7
Merged
Conversation
Setting up a new overlay file today is manual: mkdir the entry, cp/mv the file over, then run apply. That friction discourages moving files into the overlay after the fact, even though the overlay is meant to be the source of truth for gitignored personal files. adopt collapses this into one step per file: verify the target is gitignored (never touch tracked files) and not already a symlink elsewhere or shadowing existing overlay content, move it into the mirrored overlay path, and symlink it back — leaving the file in the exact "linked" state apply would produce, so a subsequent apply is a no-op. Directories are rejected rather than recursed, matching symlink-each: ghostq never links whole directories, and a directory can hold committed files alongside overlay candidates that need individual gitignore review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013mAzjNvVWGBJT81cfTSJJN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Setting up a new overlay file today is manual:
mkdirthe overlay entrydirectory,
cp/mvthe file into it, then runghostq apply. This frictiondiscourages moving existing personal files into the overlay after the fact,
even though the overlay is meant to be the durable source of truth for
gitignored, per-repo files.
ghostq adopt <file>...collapses this into one step per file:resolveContext(same identityresolution as
apply/status), rejecting files outside a git repo or in arepo with no resolvable remote identity.
(
fs.rename, with a copy+unlink fallback forEXDEVwhen the overlay liveson a different filesystem).
of link
applyproduces, so a subsequentghostq applyon that file is ano-op (
alreadyLinked), verified directly in tests.Safety guarantees
Per invariants in
AGENTS.md:git check-ignoreis skipped witha warning —
adoptnever moves a tracked file into the overlay.the checkout path is already a symlink pointing somewhere else, the file is
skipped and reported, not overwritten.
overlay entry is reported as
already-adoptedrather than re-processed.with a message to pass individual files instead, matching how
applylinksfiles individually so committed and overlay-linked files can sit side by
side in the same directory.
src/adopt.tsand returns a data structure per file(
adopted/already-adopted/skipped-not-ignored/skipped-conflict/
skipped-directory/error); onlysrc/index.tsprints, consistent withthe rest of the codebase.
Test plan
bun installbun test— 42 pass (addstest/adopt.test.tscovering: move +symlink + content preservation, idempotency bridge with
applyFiles,tracked-file skip, already-adopted no-op, overlay-conflict skip,
foreign-symlink skip, directory rejection)
bun run typecheckbun run build🤖 Generated with Claude Code
https://claude.ai/code/session_013mAzjNvVWGBJT81cfTSJJN