Jump to content

isf

From Hugo's wiki

isf (interactive shared folder) keeps a local folder and a remote one the same, both ways, over ssh. Change a file on either side and it shows up on the other a moment later.

$ isf ./proj server:proj
isf: ./proj ⇄ server:proj
  ↑ src/main.c
  ↓ notes.md
isf: in sync: 1 sent, 1 received
isf: watching for changes, Ctrl-C to stop
  ↑ src/main.c
  ↓ todo deleted

Requirements

  • Linux on both machines (isf uses inotify to see changes).
  • ssh access to the remote, with SFTP enabled (the OpenSSH default).
  • The same isf on both machines: the local one starts a copy on the remote and stops if it isn't the same version.
  • curl or wget, only for isf --update.

Installation

The releases have isf for x86_64 and aarch64, as a static binary and as an AppImage. nightly is built from every push to main.

$ curl -Lo ~/.local/bin/isf https://github.com/hugoocoto/isf/releases/download/nightly/isf-x86_64
$ chmod +x ~/.local/bin/isf

Or build it:

$ git clone --recurse-submodules https://github.com/hugoocoto/isf
$ cd isf
$ make && cp isf ~/.local/bin/

Then put the same binary on the remote, for example with scp isf server:.local/bin/isf. If it isn't in the PATH of commands run over ssh, tell isf once and it remembers:

$ isf ./proj server:proj -I .local/bin/isf

It is also available through the pm user repository. isf --update replaces isf with the newest release; run it on both machines.

Usage

isf [folder...] [[user@]host:folder] [options]

The first time, give the local folder and where it goes, like scp:

$ isf ./proj server:proj              # ./proj with ~/proj on server
$ isf ./proj server:/srv/proj         # an absolute path on the remote
$ isf ./proj me@server:proj -p 2222   # another user and port
$ isf a b server:backups/             # backups/a and backups/b

A remote folder ending in / means "inside it". After the first run isf remembers where each folder syncs to, so isf ./proj, or just isf inside the folder, is enough. It runs until Ctrl-C; with --once it syncs what is different now and exits, for scripts and cron jobs.

Options

Option Description
-p, --port PORT ssh port
-I, --isf PATH where isf is on the remote
-j, --jobs N transfer up to N files at once (default 4)
-n, --dry-run show what syncing would do and exit
--once sync what is different now and exit
-q, --quiet don't list each file
-v, --verbose show every file system event
--reset forget previous syncs: sync like the first time
--check-update, --update check for, or install, a newer release

Output

  ↑ path               sent to the remote (↓: received from it)
  ↑ path deleted       removed there because it was removed here
  ↑ path mode          only the permissions changed
  ↑ old → new          renamed on both sides
  ! path changed on both sides: kept the newest, the other one is path.isf-conflict

How changes are decided

  • If something changed on one side only, that side wins.
  • If it changed on both, the newest modification time wins, and the other version is kept as FILE.isf-conflict on both sides.
  • If one side deleted it and the other edited it, the edit wins.
  • A file kept open while it's written (a log) is synced once the writes stop for a couple of seconds.
Note "Newest" compares the clocks of the two machines, so keep them in time with NTP. isf warns at start if they disagree.

isf syncs files, folders and symlinks (as symlinks) with their permissions and modification times. It does not sync owners, groups or hard links.

Ignoring files

Put patterns in a .isfignore file at the top of the synced folder, with .gitignore-like syntax:

# any name that matches, in any directory
*.log
# a trailing / matches only directories
build/
# a leading / is relative to the folder
/secret.txt

Editor temp files (*.swp, *~, 4913, .#*) are always ignored. .isfignore is synced too, so both sides use the same patterns.

Safety

  • Files are written next to their place and renamed in, so a half-written file is never seen.
  • If a previously synced folder is empty on one side at start, isf stops instead of deleting everything on the other side.
  • If the connection drops, isf reconnects and syncs what changed meanwhile.

Limitations

  • A remote edit made while isf wasn't running, that kept the size and landed in the same second as the last sync, can be missed.
  • On network filesystems (NFS, Lustre, SMB) changes made by other machines raise no events; isf polls them every 5 seconds.
  • Linux limits inotify watches per user; very large trees can run out. isf tells you how to raise the limit.
  • IPv6 addresses need a host alias in ~/.ssh/config.

See also