Skip to content

Repository files navigation

FileTrail

English | 简体中文

FileTrail is a file synchronization tool with Git version control. It watches the files and directories you choose, syncs changes into a local Git repository, and lets you review and commit them on your terms.

Use it for dotfiles, scripts, notes, or other files spread across your machine. Keep separate macOS and Linux configurations in the same repository. Everything runs from a single executable. Built-in synchronization and version-control commands need no separate Git installation; the optional filetrail git passthrough uses system Git.

Install

Run the following from the project directory:

cargo install --path . --locked
filetrail --help

To install FileTrail and enable Tab completion in one step:

./install.sh

The script detects Bash, Zsh, or Fish from $SHELL. You can select one explicitly with ./install.sh zsh. It installs with Cargo, then configures that shell's completion. Open a new shell afterward. The installation root defaults to ${CARGO_HOME:-$HOME/.cargo}; set CARGO_INSTALL_ROOT to override it.

Agent skill

The FileTrail skill teaches an agent what FileTrail does and how to use its commands, including restoration. To install it, simply send Codex this message:

Please install this Skill: https://github.com/RinChanNOWWW/FileTrail/tree/master/skills/filetrail

You can also run Codex's GitHub skill installer manually:

python3 "${CODEX_HOME:-$HOME/.codex}/skills/.system/skill-installer/scripts/install-skill-from-github.py" \
  --repo RinChanNOWWW/FileTrail --ref master --path skills/filetrail

If the skill is on another branch or tag, replace master with that ref. The skill installs as filetrail; invoke it with $filetrail in a supporting agent environment. It provides instructions only: the agent still needs access to the FileTrail executable and the files on the machine being managed.

Tab completion and shell integration

If you installed FileTrail with cargo install, enable completion with:

filetrail completions --install

This detects your shell from $SHELL. To select a shell explicitly:

filetrail completions zsh --install
filetrail completions bash --install
filetrail completions fish --install

Run the command for the shell you use, then open a new shell. Tab completes subcommands (including daemon and service actions), options, and file paths. For example, try filetrail da<Tab>, filetrail daemon st<Tab>, or filetrail add --f<Tab>. This also enables filetrail cd to change the current shell's directory to the target repository.

Installation preserves existing shell configuration and is safe to repeat. It uses .zshrc (respecting ZDOTDIR), .bashrc and Bash's active login profile, or Fish's completion and function directories (respecting XDG_CONFIG_HOME). Home paths use $HOME in the installed hooks and command output, so your username is not embedded. Paths outside Home retain their absolute location. Completion stays in sync when you upgrade the executable at the same location. Run installation again if you move it. To remove completion, delete the marked FileTrail block from the configured files printed by the install command.

To print a completion script for manual setup, omit --install:

filetrail completions zsh

Get started

filetrail init ~/dotfiles --subdir macos
filetrail add ~/.zshrc
filetrail add ~/.config/nvim
filetrail daemon start

On Linux, use --subdir linux. Omit --subdir to save at the repository root. FileTrail creates the destination and initializes Git if needed. Adding a source immediately copies its existing files; the daemon keeps subsequent changes in sync.

Choose where files go

Sources inside Home are stored under __HOME__, preserving their Home-relative paths. All other sources are stored under __ROOT__, preserving their absolute hierarchy without the leading /. These directories sit inside the subdirectory selected during init, or directly at the repository root when it is omitted.

Source Subdirectory File in the repository
~/.zshrc macos macos/__HOME__/.zshrc
~/.config/nvim linux linux/__HOME__/.config/nvim/init.lua
/opt/scripts/build.sh macos macos/__ROOT__/opt/scripts/build.sh
/opt/scripts Omitted __ROOT__/opt/scripts/build.sh

For restoration, __HOME__ refers to the current user's Home and __ROOT__ to /. Custom target paths are not supported: preserving source paths makes the original location unambiguous. __HOME__ and __ROOT__ are reserved and cannot be used as components of --subdir.

filetrail add /opt/scripts
filetrail add ~/notes --exclude '**/*.tmp'

Directories are watched recursively. Exclusions are relative to the source root. Relative source paths are resolved from your current directory; parent-directory symlinks are resolved to their actual locations. Sources, destinations, and the application data directory must not overlap.

Restore files to this system

Select an existing FileTrail repository with init on a new machine, then restore:

filetrail init ~/dotfiles --subdir macos # Only for a profile not yet initialized
filetrail restore --dry-run
filetrail restore
filetrail restore macos/__HOME__/.zshrc macos/__HOME__/.config/nvim
filetrail restore --track macos/__HOME__/.zshrc
filetrail restore --overwrite macos/__HOME__/.zshrc

Paths are relative to the repository root, including the configured subdirectory. Supply multiple files or directories; directories are copied recursively and overlapping selections are copied once. With no paths, restore all files under the current subdirectory's __HOME__ and __ROOT__. Other subdirectories and repository files such as READMEs are not restored. __HOME__ maps to the current user's Home; __ROOT__ maps to / and requires write access at the original absolute locations. The repository's current working files are used, including uncommitted files.

By default, this only copies files and leaves management unchanged. Identical files are left alone; different local contents, file types, or permissions require --overwrite. Local directories are never replaced by files or links. Files absent from the repository are not deleted. File permissions and symlinks are preserved; symlink targets are not copied or rewritten. Restore refuses symlink ancestors, paths into the repository or application data directory, and .git paths. Nested .git entries are skipped.

--track also adds each restored file or symlink to management with deletion disabled, so extra local files in the same directory do not become managed. Compatible existing mappings retain their settings; disabled or excluded mappings must be adjusted before using --track. Files encoded under __ROOT__ that now belong inside Home can be copied, but must use the __HOME__ layout to be tracked. Empty directories are created but are not added as management entries. Afterward, ordinary synchronization flows from this system back to the repository; restore does not start the daemon or commit.

--dry-run previews copying and optional management changes without applying them. All selections and conflicts are checked before copying. An I/O error during execution can leave some files restored; fix the error and rerun the command.

Change the target or start over

To switch repositories while keeping your sources, exclusions, and deletion settings:

filetrail retarget ~/new-dotfiles
filetrail retarget ~/new-dotfiles --subdir linux
filetrail retarget ~/new-dotfiles --subdir . # Save at the repository root

Omitting --subdir keeps the current subdirectory. You can also change just the subdirectory by specifying the current repository. FileTrail creates the repository if needed and immediately syncs enabled sources to the new location. The daemon continues using the new target and retains its paused/running status.

The old files and Git history remain where they are; they are not moved or deleted. Different content already present at the new destination is reported as a conflict and kept for you to resolve. The target has changed even if this initial sync reports conflicts; use conflicts and resolve against the new repository.

To stop using a profile or initialize it again from scratch:

filetrail deinit
filetrail init ~/another-repository --subdir macos

deinit stops the daemon, uninstalls its registered startup service, and clears this profile's configuration and synchronization records. It preserves source files, repositories, Git history, logs, and shell completion. You can run it again safely. After reinitializing, add your sources and start the daemon or install the service again. Use the same --data-dir if you selected a custom profile.

Add sources from a list

filetrail add --from ./files.txt

Write one source per line. Use single or double quotes around paths containing spaces. A second column for a custom target is not supported.

# source
~/.zshrc
~/.config/nvim
/opt/scripts
"~/My Notes"
'./local scripts'

Relative source paths are resolved from the list's directory. Blank lines and # comments are allowed. Use ~ for HOME; environment variables and commands in the list are not expanded or executed. The whole list is checked before any entries are added. Editing it later does not update previously imported entries.

Manage sources

filetrail list
filetrail disable 1
filetrail enable 1
filetrail remove 1
filetrail sync
filetrail sync --dry-run

Use IDs from list. remove stops tracking a source and keeps its destination files. sync copies current changes immediately; --dry-run previews them.

Source deletions are retained at the destination by default. Enable deletion propagation when adding a source:

filetrail add ~/scripts --delete

Only previously synchronized files can be deleted. If an entire source directory becomes unavailable, FileTrail keeps its destination files. Symlinks are copied as links, not followed; Git does not track empty directories. .git is always excluded, and destination Git ignore rules apply when committing.

Review and commit

filetrail status
filetrail diff
filetrail diff -- macos/__HOME__/.config/nvim
filetrail commit
filetrail commit -m 'Update shell configuration'
filetrail commit -- macos/__HOME__/.zshrc

The daemon never commits or pushes automatically. diff includes new file contents. commit includes only managed files and refuses to proceed if other changes are already staged. Set your Git name and email before your first commit.

Without -m, FileTrail generates a message listing the selected changes:

FileTrail: sync 3 files (+1 ~1 -1)

add "macos/__HOME__/.config/nvim/init.lua"
delete "macos/__HOME__/.oldrc"
modify "macos/__HOME__/.zshrc"

To keep the destination stable while reviewing:

filetrail pause
filetrail diff
filetrail commit
filetrail resume

resume catches up with changes made while paused. Explicit sync and add commands still copy files while automatic synchronization is paused. Paths passed to diff, commit, and resolve are relative to the repository root.

Jump to the repository and run Git

With Bash, Zsh, or Fish integration installed, jump to the target repository:

filetrail completions --install # Also run once when upgrading to enable directory jumping
# Open a new shell, then:
filetrail cd

This changes the current shell's directory to the repository root, even when a --subdir is configured. Without shell integration, the executable prints the path; in Bash or Zsh you can use cd "$(command filetrail cd)". Use command filetrail cd to print the path when integration is loaded, or add --print0 for NUL-terminated output.

Run any system Git command in the target repository without changing directories:

filetrail git status
filetrail git log --oneline -10
filetrail git push origin master
filetrail --data-dir ~/filetrail-work git push origin master

This requires git on PATH and uses its normal configuration, credentials, and hooks. Put FileTrail's --data-dir before git; Git arguments, input/output, and exit codes are passed through. Synchronization waits while the Git command runs. No automatic sync, staging, or commit is added. filetrail git commit follows normal Git staging and can include any staged file; filetrail commit remains limited to managed changes.

Resolve conflicts

FileTrail reports a conflict if a destination differs from an existing source on first sync, or if you modify the destination outside FileTrail. To explicitly use the source version:

filetrail conflicts
filetrail resolve macos/__HOME__/.zshrc --use-source

You can also make both copies identical yourself and run filetrail sync again. Finish any Git merge/rebase or unresolved Git conflicts before resuming synchronization.

Run in the background

filetrail daemon start
filetrail daemon status
filetrail daemon restart
filetrail daemon stop
filetrail daemon run          # Foreground mode
filetrail daemon start --poll # Use periodic scans instead of filesystem events

For automatic startup at login, install a user service after placing the executable in a stable location:

filetrail service show
filetrail service install
filetrail service uninstall

macOS uses launchd and Linux uses systemd user services. Once installed, use service uninstall to stop the service and prevent automatic restarts.

Data directory and troubleshooting

FileTrail stores its application data in $HOME/.filetrail on both platforms. Your synchronized files and Git history live in the repository chosen during init. To use a different data directory, pass the same --data-dir to each command:

filetrail --data-dir ~/filetrail-work init ~/work-dotfiles --subdir macos
filetrail --data-dir ~/filetrail-work daemon start

Use one data directory per repository. To inspect problems or discover more options:

filetrail doctor
filetrail logs --follow
filetrail --help
filetrail add --help

For development instructions, see AGENTS.md.

About

A single-binary CLI that watches files, syncs them to a Git repository, and lets you review and commit changes on your terms.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages