{"id":13395226,"url":"https://github.com/cytopia/linux-timemachine","last_synced_at":"2025-04-12T23:30:13.998Z","repository":{"id":18047717,"uuid":"83223421","full_name":"cytopia/linux-timemachine","owner":"cytopia","description":"Rsync-based OSX-like time machine for Linux, MacOS and BSD for atomic and resumable local and remote backups","archived":false,"fork":false,"pushed_at":"2023-09-27T23:08:00.000Z","size":227,"stargazers_count":813,"open_issues_count":12,"forks_count":68,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-04-04T02:09:27.989Z","etag":null,"topics":["backup","backup-cli","backup-script","backup-utility","linux-backup","linux-time-machine","linux-timemachine","rsync","rsync-backup","rsync-backup-script","rsync-backups","rsync-time-backup","rsync-wrapper","rsyncbackup","time-machine","timemachine"],"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/cytopia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-02-26T16:29:49.000Z","updated_at":"2025-04-02T20:12:16.000Z","dependencies_parsed_at":"2024-01-14T15:22:59.772Z","dependency_job_id":"2a1a8308-8f29-4926-af7f-a1e1f14ac61e","html_url":"https://github.com/cytopia/linux-timemachine","commit_stats":{"total_commits":118,"total_committers":6,"mean_commits":"19.666666666666668","dds":"0.11016949152542377","last_synced_commit":"bc947eb998aed9f94a2772d5ab91060d3602c059"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cytopia%2Flinux-timemachine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cytopia%2Flinux-timemachine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cytopia%2Flinux-timemachine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cytopia%2Flinux-timemachine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cytopia","download_url":"https://codeload.github.com/cytopia/linux-timemachine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248647249,"owners_count":21139081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["backup","backup-cli","backup-script","backup-utility","linux-backup","linux-time-machine","linux-timemachine","rsync","rsync-backup","rsync-backup-script","rsync-backups","rsync-time-backup","rsync-wrapper","rsyncbackup","time-machine","timemachine"],"created_at":"2024-07-30T17:01:46.810Z","updated_at":"2025-04-12T23:30:13.967Z","avatar_url":"https://github.com/cytopia.png","language":"Shell","readme":"# Linux Time Machine\n\n**[Install](#tada-install)** |\n**[Uninstall](#no_entry_sign-uninstall)** |\n**[TL;DR](#coffee-tldr)** |\n**[Features](#star-features)** |\n**[How does it work](#information_source-how-does-it-work)** |\n**[Restore](#recycle-restore)** |\n**[Retention](#repeat-retention)** |\n**[Usage](#computer-usage)** |\n**[FAQ](#bulb-faq)** |\n**[Disclaimer](#exclamation-disclaimer)** |\n**[License](#page_facing_up-license)**\n\n[![Linting](https://github.com/cytopia/linux-timemachine/workflows/Linting/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=Linting)\n[![Linux](https://github.com/cytopia/linux-timemachine/workflows/Linux/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=Linux)\n[![MacOS 10](https://github.com/cytopia/linux-timemachine/workflows/MacOS-10/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=MacOS-10)\n[![MacOS 11](https://github.com/cytopia/linux-timemachine/workflows/MacOS-11/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=MacOS-11)\n[![SSH](https://github.com/cytopia/linux-timemachine/workflows/SSH/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=SSH)\n[![Tag](https://img.shields.io/github/tag/cytopia/linux-timemachine.svg)](https://github.com/cytopia/linux-timemachine/releases)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\n`timemachine` is a tiny and stable [KISS](https://en.wikipedia.org/wiki/KISS_principle) driven and [POSIX](https://en.wikipedia.org/wiki/POSIX) compliant script that mimics the behavior of OSX's timemachine.\nIt uses [rsync](https://linux.die.net/man/1/rsync) to incrementally back up your data to a different\ndirectory, hard disk or remote server via SSH. All operations are incremental, atomic and automatically resumable.\n\nBy default it uses the rsync options: `--recursive`, `--perms`, `--owner`, `--group`, `--times` and `--links`.\nIn case your target filesystem does not support any of those options or you cannot use them due\nto missing permission, you can explicitly disable them via `--no-perms`, `--no-owner`, `--no-group`, `--no-times`, and `--copy-links`.\nSee [FAQ](#bulb-faq) for examples.\n\n**Motivation**\n\nThe goal of this project is to have a cross-operating system and minimal as possible backup script\nthat can be easily reviewed by anyone without great effort.\nAdditionally it should provide one task only and do it well without\nthe need of external requirements and only rely on default installed tools.\n\n\n## :tada: Install\n```bash\nsudo make install\n```\n\n\n## :no_entry_sign: Uninstall\n```bash\nsudo make uninstall\n```\n\n\n## :coffee: TL;DR\n\nUsing [POSIX.1-2008](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html) argument syntax:\n\n```bash\n# Recursive, incremental and atomic backup (locally)\n$ timemachine /source/dir /target/dir\n\n# Recursive, incremental and atomic backup (via ssh)\n$ timemachine /source/dir user@host:target/dir\n\n# Recursive, incremental and atomic backup (via ssh with non-standard port)\n$ timemachine --port 10000 /source/dir user@host:target/dir\n\n# Append rsync options\n$ timemachine /source/dir /target/dir -- --specials --progress\n$ timemachine /source/dir /target/dir -- --specials --no-perms\n$ timemachine /source/dir /target/dir -- --archive --progress\n\n# Make the timemachine script be more verbose\n$ timemachine -v /source/dir /target/dir\n$ timemachine --verbose /source/dir /target/dir\n\n# Make the timemachine script be even more verbose\n$ timemachine -d /source/dir /target/dir\n$ timemachine --debug /source/dir /target/dir\n\n# Make the timemachine script and rsync more verbose\n$ timemachine -v /source/dir /target/dir -- --verbose\n$ timemachine --verbose /source/dir /target/dir -- --verbose\n```\n\n\n## :star: Features\n\n| Feature | Description |\n|---------|-------------|\n| **SSH or local** | Local backups as well as backups via SSH are supported. |\n| **Incremental**  | Backups are always done incrementally using rsync's ability to hardlink to previous backup directories. You can nevertheless always see the full backup on the file system of any incrementally made backup without having to generate it. This will also be true when deleting any of the previously created backup directories. See the [Backups](#backups) section for how this is achieved via rsync.\u003cbr/\u003e\u003cbr/\u003eIncremental Backups also mean that only the changes on your source, compared to what is already on the target, have to be backed up. This will save you time as well as disk space on the target disk. |\n| **Partial**      | When backing up, files are transmitted partially, so in case a 2GB movie file backup is interrupted the next run will pick up exactly where it left off at that file and will not start to copy it from scratch. |\n| **Resumable**    | Not only is this script keeping partial files, but also the whole backup run is also resumable. Whenever there is an unfinished backup and you start `timemachine` again, it will automatically resume it. It will resume any previously failed backup as long as it finally succeeds. |\n| **Atomic** \u003csup\u003e[1]\u003c/sup\u003e | The whole backup procedure is atomic. Only if and when the backup procedure succeeds, it is then properly named and symlinked. Any non-successful backup directory is either waiting to be resumed or to be deleted. |\n\n* \u003csup\u003e[1]\u003c/sup\u003e The backup process is atomic, but not the backup itself. `rsync` copies files as it finds them and in the meantime there could already be changes on the source. To achieve an atomic backup, either back up from a read-only volume or from a snapshot.\n\n\n## :information_source: How does it work?\n\n### Directory structure\n\nThe following directory structure will be created:\n```bash\n$ tree -L 1 /my/backup/folder\n.\n├── 2018-01-06__18-43-30/\n├── 2018-01-06__18-44-23/\n├── 2018-01-06__18-50-44/\n├── 2018-01-06__18-50-52/\n└── current -\u003e 2018-01-06__18-50-52/\n```\n\n`current` will always link to the latest created backup.\nAll backups are incremental except the first created one.\nYou can nevertheless safely remove all previous folders and the remaining folders will still have all of their content.\n\n### Backup strategy\n\nExcept for the first one, backups are always and automatically done **incrementally**,\nso the least amount of space is consumed.\nDue to `rsync`'s ability, every directory will still contain all files, even though they are just\nincremental backups. This is archived via hardlinks.\n```bash\n$ du -hd1 .\n497M    ./2018-01-06__18-43-30\n24K     ./2018-01-06__18-44-23\n24K     ./2018-01-06__18-50-44\n24K     ./2018-01-06__18-50-52\n497M    .\n```\n\nYou can also safely delete the initial full backup directory without having to worry about losing\nany of your full backup data:\n```bash\n$ rm -rf ./2018-01-06__18-43-30\n$ du -hd1 .\n497M    ./2018-01-06__18-44-23\n24K     ./2018-01-06__18-50-44\n24K     ./2018-01-06__18-50-52\n497M    .\n```\n\n`rsync` and [hardlinks](https://en.wikipedia.org/wiki/Hard_link) are magic :-)\n\n\n### Failure handling and resume\n\nIn case the `timemachine` script aborts (self-triggered, disk unavailable or for any other reason)\nyou can simply run it again to automatically **resume** the last failed run.\n\nThis is due to the fact that the backup process is **atomic**. During a non-complete run,\nall data will be stored in a directory named `.inprogress/`. This will hold all already\ntransferred data and will be picked up during the next run.\nOnce the backup is complete, it will be renamed and symlinked to `current`.\n```bash\n$ tree -a -L 1 /my/backup/folder\n.\n├── .inprogress/\n├── 2018-01-06__18-43-30/\n├── 2018-01-06__18-44-23/\n├── 2018-01-06__18-50-44/\n├── 2018-01-06__18-50-52/\n└── current -\u003e 2018-01-06__18-50-52/\n```\n\n\n## :recycle: Restore\n\nNo special software is required to restore your data. Backed up files can be easily browsed and\nthus copied back to where you need them. Recall the backup directory structure:\n```bash\n$ tree -L 1 /my/backup/folder\n.\n├── 2018-01-06__18-43-30/\n├── 2018-01-06__18-44-23/\n├── 2018-01-06__18-50-44/\n├── 2018-01-06__18-50-52/\n└── current -\u003e 2018-01-06__18-50-52/\n```\n\nChose a backup directory and simply copy them to where you need it:\n```bash\n# Test it out in dry run mode before applying\n$ rsync --archive --progress --dry-run /my/backup/folder/2018-01-06__18-50-52/ /src/\n\n# Apply restoration\n$ rsync --archive --progress /my/backup/folder/2018-01-06__18-50-52/ /src/\n```\n\n\n## :repeat: Retention\n\nAs decribed above this project is [KISS](https://en.wikipedia.org/wiki/KISS_principle) driven and only tries to do one job: **back up your data**.\n\nRetention is a delicate topic as you want to be sure that data is removed as intended. For this there are already well-established tools that do an excellent job and have proven themselves over time: [tmpreaper](http://manpages.ubuntu.com/manpages/precise/man8/tmpreaper.8.html) and [tmpwatch](https://linux.die.net/man/8/tmpwatch).\n\n\n## :lock: Reliability\n\n[![Linting](https://github.com/cytopia/linux-timemachine/workflows/Linting/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=Linting)\n[![Linux](https://github.com/cytopia/linux-timemachine/workflows/Linux/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=Linux)\n[![MacOS 10](https://github.com/cytopia/linux-timemachine/workflows/MacOS-10/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=MacOS-10)\n[![MacOS 11](https://github.com/cytopia/linux-timemachine/workflows/MacOS-11/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=MacOS-11)\n[![SSH](https://github.com/cytopia/linux-timemachine/workflows/SSH/badge.svg)](https://github.com/cytopia/linux-timemachine/actions?workflow=SSH)\n\nThe script is written and maintained with maximum care.\nIn order to retain a reliable and stable backup solution, a lot of effort goes into a vast amount of\n**[integration and regression tests](https://github.com/cytopia/linux-timemachine/actions)**.\nThese tests not only give you measurable confidence, but also help new contributors to not\naccidentally introduce new or old bugs.\n\n\n## :computer: Usage\n\n### Available options\n```\n$ timemachine -h\n\nUsage: timemachine [-vd]   \u003csource\u003e \u003cdest\u003e -- [rsync opts]\n\n       timemachine [-vdpi] \u003csource\u003e \u003chost\u003e:\u003cdest\u003e        -- [rsync opts]\n       timemachine [-vdpi] \u003csource\u003e \u003cuser\u003e@\u003chost\u003e:\u003cdest\u003e -- [rsync opts]\n       timemachine [-vdpi] \u003csource\u003e \u003cssh-alias\u003e:\u003cdest\u003e   -- [rsync opts]\n\n       timemachine [-vdpi] \u003chost\u003e:\u003csource\u003e        \u003cdest\u003e -- [rsync opts]\n       timemachine [-vdpi] \u003cuser\u003e@\u003chost\u003e:\u003csource\u003e \u003cdest\u003e -- [rsync opts]\n       timemachine [-vdpi] \u003cssh-alias\u003e:\u003csource\u003e   \u003cdest\u003e -- [rsync opts]\n\n       timemachine -V, --version\n       timemachine -h, --help\n\nThis shell script mimics the behavior of OSX's timemachine.\nIt uses rsync to incrementally back up your data to a different directory or remote server via SSH.\nAll operations are incremental, atomic and automatically resumable.\n\nBy default it uses --recursive --perms --owner --group --times --links.\nIn case your target filesystem does not support any of those options, you can explicitly\ndisable those options via --no-perms --no-owner --no-group --no-times and --copy-links.\n\nRequired arguments:\n  \u003csource\u003e              Local source directory\n  \u003cdest\u003e                Local destination directory.\n  \u003chost\u003e:\u003cdest\u003e         SSH host and source/destination directory on server\n  \u003cuser\u003e@\u003chost\u003e:\u003cdest\u003e  SSH user, SSH host and source/destination directory on server\n  \u003cssh-alias\u003e:\u003cdest\u003e    SSH alias (defined in ~/.ssh/config) and source/destination directory on server\n\nOptions:\n  -p, --port            Specify alternative SSH port for remote backups if it is not 22.\n  -i, --identity        Specify path to SSH key.\n  -v, --verbose         Be verbose.\n  -d, --debug           Be even more verbose.\n\nMisc Options:\n  -V, --version         Print version information and exit\n  -h, --help            Show this help screen\n\nExamples:\n  Simply back up one directory recursively\n      timemachine /home/user /data\n  Do the same, but be verbose\n      timemachine -v /home/user /data\n  Append rsync options and be very verbose\n      timemachine -d /home/user /data -- --progress --verbose\n  Log to file\n      timemachine -v /home/user /data \u003e /var/log/timemachine.log 2\u003e /var/log/timemachine.err\n\nDocumentation:\n  View more examples at: https://github.com/cytopia/linux-timemachine\n```\n\n### Use with cron\n\nThe following can be used as an example crontab entry. It assumes you have an external disk (NFS, USB, etc..) that mounts at `/backup`. Before adding the crontab entry, ensure the filesystem in `/backup` is mounted and use:\n\n```bash\n$ touch /backup/mounted\n```\n\nThis guards against accidentally backing up to an unmounted directory\n\nNext, add the following to crontab using `crontab -e` as whichever user you intend to run the backup script as. You may need to place this in the root crontab if you are backing up sensitive files that only root can read\n\n```bash\n0 2 * * * if [[ -e /backup/mounted ]]; then /usr/local/bin/timemachine /home/someuser /backup; fi\n```\n\nThis will cause `timemachine` to run at 2AM once per day. Since `timemachine` keeps track of backups with granularity up to the hour, minute and second, you could have it run more than once per day if you want backups to run more often.\n\n\n## :bulb: FAQ\n\n**Should I add trailing directory slashes (`/`)?**\n\nTrailing directory slashes only matter for the source directory and will not make a difference\nif added to the destination directory.\n```bash\n# The following backs up the contents of the src directory\n$ timemachine src/ dst/\n$ tree -L 2 /dst\n.\n├── 2018-01-06__18-43-30/\n│   └── file.txt\n└── current -\u003e 2018-01-06__18-43-30/\n```\n\n```bash\n# The following backs up the the src directory itself\n$ timemachine src dst/\n$ tree -L 3 /dst\n.\n├── 2018-01-06__18-43-30/\n│   └── src\n│       └── file.txt\n└── current -\u003e 2018-01-06__18-43-30/\n```\n\n**How to dry-run the backup?**\n```bash\n$ timemachine src/ dst/ -- --dry-run\n```\n\n**How to use a non-standard SSH port?**\n```bash\n$ timemachine --port 1337 src/ user@host:dst/\n```\n\n**How to use SSH aliases from `~/.ssh/config`?**\n```bash\n$ cat ~/.ssh/config\nHost my-ssh-alias\n  HostName     192.168.0.1\n  Port         1234\n  User         john\n  IdentityFile ~/.ssh/id_rsa__alternative_key\n```\n```bash\n$ timemachine src/ my-ssh-alias:dst/\n```\n\n**How to speed up remote backups?**\n```bash\n# With  this option, rsync compresses the file data as it is sent to the des‐\n# tination machine, which reduces the amount of  data  being  transmitted\n$ timemachine src/ user@host:dst/ --compress\n```\n\n**How to preserve ACLs?**\n```bash\n$ timemachine src/ dst/ -- --acls\n```\n\n**How to preserve extended attributes?**\n```bash\n$ timemachine src/ dst/ -- --xattrs\n```\n\n**How to disable preserving file and directory permissions?**\n```bash\n$ timemachine src/ dst/ -- --no-owner --no-perms\n```\n\n**How to disable preserving modification time?**\n```bash\n$ timemachine src/ dst/ -- --no-times\n```\n\n**How to copy the content instead of a symlink?**\n```bash\n# This is useful in case your file system does not support symlinks.\n# It is recommended to read rsync man page about symlinks to be sure\n# about what you are doing\n$ timemachine src/ dst/ -- --copy-links --safe-links\n$ timemachine src/ dst/ -- --copy-links --safe-links --keep-dirlinks\n```\n\n**How to ensure all files in the back up have the ownership of current user?**\n```bash\n# Regardless of who owns the files, ensure the backup has uid and gid of current user\n# This will only work if you have read-permission on all files.\n$ timemachine src/ dst/ -- --no-owner --no-group\n\n# If you do not have permission to read all files, you require sudo or root permission.\n# The following will instruct rsync to ensure the backed up data has the uid and gid\n# of the desired user.\n$ sudo timemachine src/ dst/ -- --chown=\u003cuser\u003e:\u003cgroup\u003e\n```\n\n\n## :exclamation: Disclaimer\n\nBackups are one of the most important things. We all care about our data and want it to be safe,\nso do not blindly trust scripts when it comes to backups!\nDo **[review the code](https://github.com/cytopia/linux-timemachine/blob/master/timemachine)**,\nit is not too complex and kept as short as possible. Have a look at how much effort goes into the\n**[integration tests](https://github.com/cytopia/linux-timemachine/actions)** to provide measurable\nstability.\n\nLearn about **[rsync](https://linux.die.net/man/1/rsync)** it is a very powerful tool and you might\neven be able to just use this for backups.\n\nThere are many other backup solutions out there that might be a better fit for your needs. Do your\nown research, look at GitHub issues, source code, integration tests and try them out as well.\n\n\n## :octocat: Contributing\n\nSee **[Contributing guidelines](CONTRIBUTING.md)** to help to improve this project.\n\n\n## :page_facing_up: License\n\n**[MIT License](LICENSE.md)**\n\nCopyright (c) 2017 **[cytopia](https://github.com/cytopia)**\n","funding_links":[],"categories":["Shell"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcytopia%2Flinux-timemachine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcytopia%2Flinux-timemachine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcytopia%2Flinux-timemachine/lists"}