Skip to main content

SSH directory synchronization library and CLI

Project description

SSHMirror

Sync a working directory with a remote server over SSH, inspect diffs before applying changes, and keep a lightweight local history for rollback-oriented workflows.

SSHMirror is both:

  • a Python library you can import;
  • a CLI you can run inside a project folder;
  • a sync workflow that keeps local and remote changes inspectable.

It can also be used as a lightweight sync workflow for a shared project: multiple developers can make changes to the same remote-backed codebase and inspect differences before pulling or pushing updates.

Internet access is not required for SSHMirror itself. It only needs network access to the target SSH host or Docker host you are synchronizing with.

When you run sshmirror without arguments, it opens an interactive menu. Depending on project state, the menu can include:

  • Create sshmirror.config.yml
  • Create sshmirror.ignore.txt
  • Initialization
  • Sync local and remote
  • Status
  • View current changes
  • Versions...
  • History inside Versions...
  • Compare inside Versions...
  • Pull only
  • Stash changes
  • Restore stashed changes
  • Discard...
  • Discard all local changes inside Discard...
  • Discard selected files inside Discard...
  • Downgrade remote version
  • Test connection
  • Exit

Why It Stands Out

  • Preview first. Inspect current file changes and version-to-version diffs before syncing. 🔍
  • Built for real SSH workflows. Passwords, SSH keys, passphrases, and ssh-agent fallback are supported. 🔐
  • Keeps local state. SSHMirror stores version and migration metadata under .sshmirror/. 🗂️
  • Works as a library or a command-line tool. 🐍
  • Useful for team workflows. Several developers can work on one project and sync changes through the same remote environment. 🤝
  • Optional remote container restart after sync. 🐳

Install 🚀

pip install sshmirror

For local development:

pip install -e .

Quick Start ⚡

  1. Create a config file:

    sshmirror
    

    On first interactive launch, SSHMirror can create sshmirror.config.yml for you.

  2. Start from this minimal config:

    host: '192.168.12.22'
    port: '50022'
    username: 'root'
    localdir: '.'
    remotedir: '/app'
    author: your-name
    
  3. Check status or connect-test before syncing:

    sshmirror --status
    sshmirror --test-connection
    

Example Configuration ⚙️

The full example lives in sshmirror.config.example.yml.

Supported auth patterns:

  • password auth;
  • private key auth;
  • private key with passphrase;
  • default SSH keys or ssh-agent when no key and no password are provided.

Example with optional container restart:

host: '192.168.12.22'
port: '50022'
username: 'root'
localdir: '.'
remotedir: '/app'
author: your-name

restart_container:
   # Optional. Restart a local container on the same machine where sshmirror runs.
   # Do not combine with host/port/username or SSH auth fields.
   # local: true

   # Optional. If omitted, host/port/username are reused from the main SSH config.
   # host: '192.168.12.22'
   # port: '23322'
   # username: user
  sudo: true
  container_name: testcontainer

restart_container supports two modes:

  • remote Docker host restart via SSH;
  • local restart on the same machine where sshmirror is running by setting restart_container.local: true.

If host, port, or username are not specified for remote mode, SSHMirror uses the main connection values.

CLI Commands 🧰

sshmirror --help

Main non-interactive flags:

  • --status show local and remote sync status;
  • --current-diff inspect current local versus remote differences;
  • --version-diff inspect changes between remote versions;
  • --pull only pull from remote;
  • --stash-changes stash local changes before syncing;
  • --restore-stash restore previously stashed changes;
  • --discard discard all local changes;
  • --discard-files <paths...> discard only selected files;
  • --downgrade downgrade remote version;
  • --test-connection validate SSH access to the remote host and configured Docker host.

Library Usage 📦

from sshmirror import SSHMirror, SSHMirrorConfig

mirror = SSHMirror(
    config=SSHMirrorConfig(
        host='127.0.0.1',
        port=22,
        username='root',
        localdir='.',
        remotedir='/app',
    )
)

The public API is exported from sshmirror/init.py.

Project Layout

sshmirror/
  sshmirror/          # importable package
  tests/              # smoke tests
  pyproject.toml      # packaging metadata
  sshmirror.config.example.yml

Development 🛠️

Run tests:

python -m unittest discover -s tests -p "test_*.py"

Build locally:

python -m build

Changelog

Latest release notes live in CHANGELOG.md.

Status

This repository is structured as a Python package with a CLI entry point. If you plan to publish to PyPI, keep package metadata, README, and license in sync with actual behavior.

Changelog

0.1.24

Changed

  • Displayed the current sshmirror version unobtrusively when starting the interactive CLI.
  • Reworked the Status view into a staged overview with structured local, remote, and live-diff panels.

Fixed

  • Stopped Ctrl+C in the interactive menu from surfacing a UserAbort error message.
  • Prevented concurrent client syncs with a remote lock file that blocks parallel runs and expires automatically after 5 minutes.
  • Returned interactive version history and compare lists to the same newest-first page after backing out of a version view.
  • Fully cleared push and pull preview tables after repeated invalid yes/no confirmation input.
  • Corrected force-pull/discard migration direction so local-only files are deleted and remote-only files are pulled from the server.

0.1.23

Changed

  • Increased the interactive version history message column width to 40 characters for easier reading.
  • Returned Back from History version inspection to the same history page instead of resetting to the first page.
  • Returned Back from Versions compare to base and target selection while preserving both version list pages.
  • Highlighted the currently synced project version in interactive version lists.

Fixed

  • Made Ctrl+C in the interactive menu close sshmirror cleanly without showing an error.

0.1.22

Added

  • Saved the sshmirror version in generated directory version metadata and added a compatibility guard for future incompatible version formats.

Changed

  • Clarified push and pull confirmation prompts with explicit sync directions for local and remote changes.
  • Removed the default highlight from History in the Versions submenu for a cleaner interactive menu.
  • Returned Back from History version inspection to the version list instead of exiting history browsing.

Fixed

  • Made yes/no confirmation prompts accept answers across Russian and English keyboard layouts, including mistyped layout input.

0.1.21

Fixed

  • Reversed View current changes create/delete labels so they reflect the actual sync direction instead of the old server-oriented wording.
  • Restored push and pull confirmation prompts so the preview table no longer blocks interactive input before sync starts.

0.1.20

Changed

  • Reworked downgrade to match the push and pull preview flow with clearer confirmation, live status updates, and post-downgrade sync.
  • Updated View current changes to use the same file-change list format and selection flow as version comparison.
  • Renamed the interactive Pull & Push menu action to Sync local and remote for clearer CLI wording.
  • Grouped discard actions into a Discard submenu and marked submenu items with ... in the interactive CLI.
  • Added a live progress indicator during full local/remote project scans so long verification steps no longer look stuck.

Fixed

  • Cleared the preview table before showing live push and pull progress so sync runs no longer leave duplicate tables in the terminal.
  • Kept the entered push version description visible in the terminal after confirmation instead of clearing it with the preview screen.

0.1.19

Fixed

  • Restored the restart_container prompt after successful push, including fast-path syncs where the full post-push compare is skipped.

Added

  • Added restart_container.local: true to restart a Docker container on the same machine where sshmirror is running, without an extra SSH Docker host connection.

0.1.18

Fixed

  • Fixed a missing uuid import in the remote push path which caused NameError during metadata file creation.

0.1.17

Fixed

  • Moved push and pull confirmation prompts ahead of the live sync table so interactive confirmation and version description input work correctly.

0.1.16

Changed

  • Replaced the interactive View version changes menu item with a Versions submenu containing History and Compare.
  • Added automatic previous-version diff browsing for Versions -> History.
  • Reworked push and pull execution so the existing preview table stays on screen and the Status column updates live during synchronization.
  • Made version descriptions mandatory during push instead of silently defaulting to update.

Fixed

  • Removed duplicate visible CLI actions for force-discarding local changes, leaving a single user-facing discard action.
  • Skipped the expensive full project re-compare after a normal push when no sync hook commands are configured.
  • Cleared the temporary Connect to remote... line before interactive version lists are shown.
  • Adjusted version pagination controls so Older versions appears before the version list and Newer versions appears after it.
  • Made remote push synchronization atomic by rolling back remote changes when any file sync step fails.
  • Switched generated downgrade scripts to relative paths so rollback metadata no longer embeds absolute remote project paths.

0.1.15

Changed

  • Improved interactive version history rendering with fixed-width columns for version number, timestamp, author, uid, and message.
  • Improved file change browsing so changed, created, and deleted entries are shown together with clearer color-coded styling.
  • Improved push and pull previews with structured summary panels and color-coded action tables before confirmation.

0.1.14

Changed

  • Highlighted the selected base version during target version selection so the comparison source stays visible in interactive history browsing.

Fixed

  • Removed duplicated version history rendering so interactive diff browsing shows a single styled selection list instead of both a table and a separate prompt list.

0.1.13

Fixed

  • Fixed interactive questionary prompts inside async CLI flows so they no longer fail with asyncio.run() cannot be called from a running event loop.
  • Fixed version and diff browsing prompts to run safely while the CLI event loop is active.

0.1.12

Fixed

  • Fixed Ctrl+C handling in interactive menus so cancellation exits cleanly instead of falling back to plain input.
  • Fixed prompt cancellation handling for both questionary prompts and plain-input fallback paths.

0.1.11

Changed

  • Finalized interactive diff browsing so version pages open with the newest item on the current page selected by default.
  • Restricted textual diff inspection to inspectable changed files only.

Fixed

  • Prevented oversized changed files from being selectable in interactive diff views.

0.1.10

Changed

  • Reworked View version changes for large version histories.
  • Replaced full-history rendering with interactive paginated browsing.
  • Improved version timestamp presentation in interactive history views.
  • Added colored tabular rendering and numeric shortcuts for version selection.

Added

  • Added lazy remote paging for interactive version history browsing.
  • Added author display in interactive version history views.
  • Added a 50-character validation limit for version descriptions.

0.1.9

Fixed

  • Fixed sudo password authentication for restart_container.

Added

  • Added step-by-step Docker host diagnostics for Docker host checks.

0.1.8

Fixed

  • Fixed restart_container connection handling.

Changed

  • Removed deprecated restart_container.user support and standardized on restart_container.username.

Added

  • Added startup validation for the full configuration, including restart_container consistency checks.

0.1.7

Changed

  • Optimized local and remote scanning so ignored directories are pruned instead of scanned and filtered after traversal.

0.1.6

Fixed

  • Fixed postponed annotation evaluation and runtime annotation handling.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sshmirror-0.1.24.tar.gz (67.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sshmirror-0.1.24-py3-none-any.whl (51.8 kB view details)

Uploaded Python 3

File details

Details for the file sshmirror-0.1.24.tar.gz.

File metadata

  • Download URL: sshmirror-0.1.24.tar.gz
  • Upload date:
  • Size: 67.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for sshmirror-0.1.24.tar.gz
Algorithm Hash digest
SHA256 66ad0231e9b04150f60550c8c0d7df0bcd6d6846e9f4772e55c12799867ffbc3
MD5 0214bfeee88e7d4b536972feda152839
BLAKE2b-256 73b3ff319b47c43619a1468a1466786f81856bc2669877760e0570981a9cd582

See more details on using hashes here.

File details

Details for the file sshmirror-0.1.24-py3-none-any.whl.

File metadata

  • Download URL: sshmirror-0.1.24-py3-none-any.whl
  • Upload date:
  • Size: 51.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for sshmirror-0.1.24-py3-none-any.whl
Algorithm Hash digest
SHA256 273d0c17b396cb908b6375aaec0e881635abb9e311a243f673935c1d313f5855
MD5 e6802a6cbbbd5802a8b0cb3cd62bc658
BLAKE2b-256 8913b5541ffd21d469c5f2ab0da505c6e1f23ff36e7088f52da0a49dbd0c7dd9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page