{"id":21236663,"url":"https://github.com/maxg87/root-subvol-snapshot","last_synced_at":"2025-06-11T05:04:19.144Z","repository":{"id":130667139,"uuid":"438188364","full_name":"MaxG87/root-subvol-snapshot","owner":"MaxG87","description":"Script to snapshot all top level subvolumes on an BtrFS","archived":false,"fork":false,"pushed_at":"2024-10-02T18:53:00.000Z","size":1149,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-11T05:03:28.601Z","etag":null,"topics":["backup","btrfs","btrfs-snapshots"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MaxG87.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2021-12-14T09:16:08.000Z","updated_at":"2024-10-02T18:52:40.000Z","dependencies_parsed_at":"2025-01-21T18:45:12.852Z","dependency_job_id":"8faf056d-1fab-4536-acd5-b3cb5a44088a","html_url":"https://github.com/MaxG87/root-subvol-snapshot","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaxG87%2Froot-subvol-snapshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaxG87%2Froot-subvol-snapshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaxG87%2Froot-subvol-snapshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaxG87%2Froot-subvol-snapshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MaxG87","download_url":"https://codeload.github.com/MaxG87/root-subvol-snapshot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaxG87%2Froot-subvol-snapshot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259204800,"owners_count":22821157,"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","btrfs","btrfs-snapshots"],"created_at":"2024-11-21T00:13:12.397Z","updated_at":"2025-06-11T05:04:19.119Z","avatar_url":"https://github.com/MaxG87.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# root-subvol-snapshot\n\nScript to snapshot all top level subvolumes on an BtrFS\n\n## Installation\n\nEither `sudo install snapshot /usr/local/bin` or `install snapshot ~/.local/bin`.\n\n## Usage\n\nThis section will cover how to use the program. First it will be explained what\nto expect when interacting manually with the program, then some suggestions for\nautomated usage will be given.\n\n[![asciicast](https://asciinema.org/a/523387.svg)](https://asciinema.org/a/523387)\n\n### Manual Interaction\n\nThis section assumes that the script is available via `$PATH` under the name\n`snapshot`.\n\n- There is a help message available via `snapshot --help`.\n- For normal usage, `snapshot` is sufficient. It will create snapshots and\n  delete these older than 60 days.\n- Running `snapshot --max-age N` allows to set the maximum age in days\n  explicitly. This is very helpful if one runs out of disk space.\n- It is not possible to use this script to remove old snapshots without\n  creating a new one. Since snapshots do not consume space, this feature does\n  not seem to be worth the effort.\n- It is safe to run this script on non-BtrFS devices. It will print a brief\n  message and exit with exit code 0.\n\nThe default value of 60 days was chosen as good-fit for the author of this\nscript.\n\n### Embedding to Automated Workflows\n\nThe author configured a systemd service to create a snapshot at every boot. For\nthis, the script was installed to `/usr/local/bin`, so it is available at boot\nfor the root user. Then, the provided service file was copied to\n`/etc/systemd/system` and enabled using `systemctl enable\nroot-subvol-snapshot.service`.\n\n## Directory layout\n\nRecall that the root of a BtrFS is not necessarily the `/` of the running\nsystem. The root of a BtrFS is the subvolume with ID 0.\n\nThis script assumes that all subvolumes to snapshot are located directly at the\nroot of your BtrFS file system. Lets say your device is `$DEVICE`. Then the\nfollowing commands should produce the following output:\n\n```bash\n$ sudo mount -o subvolid=0 \"$DEVICE\" /mnt\n$ ls /mnt\n@ @home @snapshots shared\n```\n\nHere, the entries `@`, `@home` and `shared` are independent subvolumes which\nshall be snapshotted into `@snapshots`.\n\nPlease note that `@snapshots` is listed here because `snapshot` would create it\nright there. It is a subvolume itself. Some additional logic prevents that\n`snapshot` would try to create a snapshot of `@snapshots`. See\n[here](#restoring-from-snapshots) on the benefits of that.\n\nThe content of `@snapshots` will look similar to the following example:\n\n```bash\n$ sudo mount -o subvolid=0 \"$DEVICE\" /mnt\n$ tree -L2 /mnt/@snapshots\n/mnt/@snapshots\n├── 2021-10-14_14:38:04\n│  ├── @\n│  ├── @home\n│  └── shared\n├── 2021-10-14_14:38:28\n│  ├── @\n│  ├── @home\n│  └── shared\n├── 2021-10-15_08:46:58\n│  ├── @\n│  ├── @home\n│  └── shared\n└── 2021-12-13_10:31:52\n   ├── @\n   ├── @home\n   └── shared\n```\n\nHere, `@`, `@home` and `shared` are read-only subvolumes which were created as\nsnapshots of their respective top level correspondents. The parent folder name\nstates when the snapshot was created.\n\n## Restoring from snapshots\n\n### Undoing accidental deletes\n\nIn order to recover lost files, one can mount the snapshots subvolume to access\nthem there. Mounting them can be done via\n\n```shell\nsudo mount -o subvol=@snapshots $DEVICE_OF_ROOT /mnt\n```\n\nNow the snapshots are available at `/mnt`. They are grouped in subdirectories\nwith their creation times. One can simply `cd` into these and copy the lost\nfiles or directories somewhere else.\n\nSince the snapshots are created read-only, it should be impossible to alter\nthem.\n\n### Restoring an old version of the subvolumes\n\nSometimes recovering files that were accidentally deleted is not enough. If it\nis unclear what has to be undone to get rid of an undesired effect, it might be\nhelpful to restore a previous state completely. One example probably everyone\nhas experienced once would be calling `rm -rf /` in the wrong location. Another\nexample experienced by the author was that after experienting with GPU driver\nconfigurations the graphical display did not work anymore.\n\nIt is easiest to restore subvolumes using a live system. Some subvolumes might\nbe recoverable from the running system too, but this guide does not cover that.\n\nFrom inside the live system, first the root subvolume must be mounted:\n\n```shell\nDEVICE_OF_ROOT=/dev/mapper/ssd-root  # insert your device here\nsudo mount -o subvolid=0 \"$DEVICE_OF_ROOT\" /mnt\n```\n\nThen all subvolumes are available under `/mnt`. For all subsequent commands it\nis assumed that they are run from inside the mount directory.\n\n```shell\ncd /mnt\n```\n\nFirst the subvolume must be removed:\n\n```shell\nSUBVOLUME=@  # insert your subvolume here\nsudo btrfs subvolume delete \"$SUBVOLUME\"\n```\n\nThen the desired snapshot must be snapshotted into the old location:\n\n```shell\nTIMESTAMP=\"2021-11-14_10:59:11\"  # insert your timestamp here\nSNAPSHOT=\"@snapshots/$TIMESTAMP/$SUBVOLUME\nsudo btrfs subvolume snapshot \"$SNAPSHOT\" \"$SUBVOLUME\"\n```\n\nIn case the subvolume that contains `/` is restored, the default subvolume must\nbe set, so it will be mounted automatically by Grub.\n\n```shell\nsudo btrfs subvolume show \"$SUBVOLUME\"\n# read the subvolume id from the output\nSUBVOLUME_ID=7331  # insert the correct value here\nsudo btrfs subvolume set-default \"$SUBVOLUME_ID\" .\n```\n\n## TODO\n\n- [Rewrite in Rust](https://github.com/ansuz/RIIR)\n- Currently snapshots are grouped by date. Maybe a grouping by device can be\n  provided additionally. Given how fast snapshots can be created and how few\n  disk space they use, one could have both groupings simultaneously.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxg87%2Froot-subvol-snapshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxg87%2Froot-subvol-snapshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxg87%2Froot-subvol-snapshot/lists"}