{"id":51098013,"url":"https://github.com/gastonmorixe/macback","last_synced_at":"2026-06-24T08:02:16.374Z","repository":{"id":346921095,"uuid":"1192160937","full_name":"gastonmorixe/macback","owner":"gastonmorixe","description":"A powerful, interactive macOS backup and restore CLI","archived":false,"fork":false,"pushed_at":"2026-03-26T06:16:47.000Z","size":1629,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-26T22:57:58.902Z","etag":null,"topics":["apple","backup","backup-script","config","mac","mac-apps","macos","time-machine"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gastonmorixe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-26T00:23:52.000Z","updated_at":"2026-03-26T06:16:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gastonmorixe/macback","commit_stats":null,"previous_names":["gastonmorixe/macback"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/gastonmorixe/macback","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gastonmorixe%2Fmacback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gastonmorixe%2Fmacback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gastonmorixe%2Fmacback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gastonmorixe%2Fmacback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gastonmorixe","download_url":"https://codeload.github.com/gastonmorixe/macback/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gastonmorixe%2Fmacback/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34722710,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apple","backup","backup-script","config","mac","mac-apps","macos","time-machine"],"created_at":"2026-06-24T08:02:14.227Z","updated_at":"2026-06-24T08:02:16.365Z","avatar_url":"https://github.com/gastonmorixe.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/logo.png\" alt=\"macback\" height=\"300\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003emacback\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eInteractive macOS backup and restore CLI\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/gastonmorixe/macback/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/gastonmorixe/macback/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.shellcheck.net/\"\u003e\u003cimg src=\"https://img.shields.io/badge/linted%20with-ShellCheck-brightgreen\" alt=\"ShellCheck\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.apple.com/macos/\"\u003e\u003cimg src=\"https://img.shields.io/badge/platform-macOS-lightgrey\" alt=\"Platform: macOS\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**macback** backs up and restores your entire macOS environment: files, configs, Homebrew packages, system metadata, and more. It runs in an **interactive terminal UI** with smart defaults that exclude caches, build artifacts, and iCloud clutter automatically. Built entirely in Bash, powered by [rclone](https://rclone.org/).\n\n## ✨ Features\n\n- 🎛️ **Interactive TUI**: arrow keys, vim bindings (`j`/`k`), `/` filtering, and `Space` multi-select\n- 📦 **Modular components**: back up files, Homebrew, keychain metadata, launchd metadata, and system snapshots independently\n- 🧠 **Smart defaults**: iCloud paths, caches, `node_modules`, build artifacts, and other rebuildables are excluded automatically\n- 🔄 **rclone-powered**: reliable file transfer with progress reporting and integrity verification\n- 🛡️ **Destination guard**: supervises `rclone` and pauses the backup if the selected volume disappears, remounts elsewhere, or no longer matches the original mount identity\n- 🔒 **SHA256 checksums**: `rclone check` verifies that backups are complete and correct\n- 📋 **JSON manifests**: spec versioning for structured metadata and forward compatibility\n- ⏸️ **Resume support**: pick up interrupted backups without re-copying transferred files\n- 🎯 **Granular restore**: choose which components, paths, and individual app configs to restore\n- 🏥 **Doctor command**: diagnose and fix backup health, permissions, and integrity issues\n- 🧪 **Comprehensive tests**: unit + integration + PTY coverage powered by BATS\n- 🔐 **Runs as root**: full access to system files and Library data, with automatic user detection\n\n## 📦 What Gets Backed Up\n\n| Component | Contents |\n|---|---|\n| **Files** | Projects, Documents, Desktop, Downloads, SSH keys, GPG keys, shell configs, dotfiles, Library preferences, Mail, Messages, LaunchAgents |\n| **Homebrew** | Brewfile, formula/cask lists, taps, leaves, services. Everything needed to reconstruct your dev environment |\n| **Keychain metadata** | Keychain discovery and locations (metadata only, no secrets exported) |\n| **Launchd metadata** | User LaunchAgents and custom system LaunchDaemons/LaunchAgents |\n| **System snapshot** | macOS version, machine serial, hostname, full application inventory |\n\n## 🚫 What Gets Excluded\n\nmacback skips things you can rebuild:\n\n- ☁️ **iCloud**: Mobile Documents, CloudStorage, iCloud app support\n- 🗑️ **System caches**: `.DS_Store`, Library Caches/Logs/WebKit, Xcode DerivedData\n- 📦 **Package caches**: `node_modules`, `.pnpm-store`, `.yarn/cache`, `.bun/install/cache`\n- 🔨 **Build artifacts**: `__pycache__`, `.pytest_cache`, `.gradle`, `target/`, `.terraform`\n- 🔌 **Socket files**: `.gnupg/S.*`, `*.sock`, agent sockets\n\nAll defaults are customizable through the **interactive rules editor** during backup.\n\n## 📋 Requirements\n\n- **macOS** (tested on macOS 13+)\n- **Bash 4+** (ships with macOS or install via Homebrew)\n- **[rclone](https://rclone.org/)**: `brew install rclone`\n- **Homebrew** (optional, only needed for the Homebrew component)\n\n## 🚀 Installation\n\n```bash\ngit clone https://github.com/gastonmorixe/macback.git\ncd macback\nmake bootstrap   # checks for shellcheck and bats-core\n```\n\n## 📖 Usage\n\n### Interactive mode\n\n```bash\nsudo bash ./macback\n```\n\nOpens the TUI main menu:\n\n```\nmacback\nmacOS backup and restore\n\n  Mode              Interactive\n  Primary user      youruser\n  Primary home      /Users/youruser\n\n  ❯ Backup          Create a new backup run\n    Restore         Restore from an existing backup\n    Inspect         View backup metadata and verification state\n    Doctor          Check and fix backup health and permissions\n    Help            Usage information\n    Quit            Exit the tool\n```\n\n### Direct commands\n\n```bash\nsudo bash ./macback backup     # guided backup flow\nsudo bash ./macback restore    # guided restore flow\nsudo bash ./macback inspect    # inspect an existing backup\nsudo bash ./macback doctor     # check and fix backup health\nsudo bash ./macback help       # show usage information\n```\n\n## ⌨️ TUI Controls\n\n| Key | Action |\n|-----|--------|\n| `↑` / `k` | Move up |\n| `↓` / `j` | Move down |\n| `Enter` | Select / Confirm |\n| `Space` | Toggle selection (multi-select) |\n| `a` | Select all visible |\n| `u` | Unselect all visible |\n| `/` | Filter / Search |\n| `q` | Cancel / Back |\n\n## 🛡️ Destination Safety\n\nFor local-disk backups, `rclone` only sees a filesystem path. It does not know that `/Volumes/My Disk` is supposed to remain bound to the same physical external drive for the entire run. Because of that, macback wraps the file-copy/check steps with a parallel destination guard.\n\n- Before `rclone` starts, macback records the selected destination mount root, filesystem device id, and volume UUID when available.\n- While `rclone` runs, a watcher checks that identity every 2 seconds.\n- If the destination disappears or remounts under a different `/Volumes/...` path, macback stops `rclone` and pauses the backup instead of trusting the stale pathname.\n- If the same volume UUID comes back under a new mount path, macback can offer to continue the same run on the remounted volume.\n- Stale `/Volumes/...` directories that are not real mounted volumes are rejected before a run is created or resumed.\n- File backups use `rclone --inplace` to avoid `.partial -\u003e final` rename failures on external filesystems.\n- Backup asks you to choose a speed profile:\n  - `Normal`: safer defaults, full `rclone check` on new runs\n  - `Fast`: more parallelism, skips the long post-copy `rclone check`\n  - `Ultrafast`: highest parallelism, skips full verification and compares by size only\n- When you resume an existing backup run, macback always skips the full post-copy `rclone check` so the restart path focuses on copying what is still missing.\n\nThis is a strong supervisory guard, not a per-write guarantee. Writes already in flight when the destination changes may still complete or fail before the watcher stops `rclone`.\n\n## 🏗️ Architecture\n\n```\nmacback              # main entrypoint\nlib/\n  common.sh          # environment detection, utilities, manifest discovery\n  ui.sh              # terminal UI framework (colors, selectors, widgets)\n  templates.sh       # backup rule template expansion (@HOME@ tokens)\n  filter.sh          # rclone filter generation\n  destination.sh     # destination volume selection, mount identity capture, remount lookup\n  manifest.sh        # manifest creation, validation, integrity checks\n  components.sh      # backup components plus the rclone destination watcher/pause flow\n  restore.sh         # restore workflows, path remapping, permission reconciliation\ntemplates/\n  include-paths.txt.template      # default paths to back up\n  exclude-patterns.txt.template   # default exclusion patterns\n```\n\nBackups are stored on the destination volume under `macback/\u003cmachine-id\u003e/\u003ctimestamp\u003e/`:\n\n```\nmeta/\n  run.json              # run metadata (timestamps, source info, versions)\n  manifest.json         # component flags and restore defaults\n  include-paths.txt     # resolved include rules\n  exclude-patterns.txt  # resolved exclude patterns\n  integrity/            # SHA256 checksums and rclone verification results\ncomponents/\n  files/rootfs/         # filesystem backup (mirrored directory tree)\n  brew/                 # Brewfile, formula/cask lists, taps\n  system/               # system facts, app inventory\n  keychain/             # keychain metadata\n  launchd/              # launchd plist inventory\n```\n\n## 🧑‍💻 Development\n\n```bash\nmake bootstrap   # check dev dependencies (shellcheck, bats-core)\nmake lint        # run shellcheck on all scripts\nmake test        # run full BATS test suite (unit + integration)\nmake check       # lint + test\n```\n\n## 📄 License\n\n[MIT](LICENSE). [Gaston Morixe](https://gastonmorixe.com/) 2026\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgastonmorixe%2Fmacback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgastonmorixe%2Fmacback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgastonmorixe%2Fmacback/lists"}