dvs get reads the meta files, finds the matching blobs in storage, and writes the contents back to their original paths. It is the inverse of add: the loop to run after re-cloning a project whose data is not on disk. Pass paths, a glob, or both.

Usage: dvs get [OPTIONS] [PATHS]...

Arguments:
  [PATHS]...

Options:
  -g, --glob <GLOB>        Select files by glob pattern
  -r, --recursive          Recurse into subdirectories of directory inputs
      --json               Output results as JSON
      --dry-run            Show what would be retrieved without writing files
      --threads <THREADS>  Threads (0 = auto-detect)
  -h, --help               Print help

🔗Options

FlagArgumentDefaultBehavior
[PATHS]...pathsnoneFiles to retrieve.
-g, --globpatternnoneLibrary-expanded glob, literal path separator (use ** to recurse).
-r, --recursiveflagoffWalk subdirectories of directory inputs. Without it, a directory retrieves only its direct children.
--dry-runflagoffReport what would be retrieved; write nothing.
--threadsinteger0 (auto)Thread pool size for this command.
--jsonflagoffEmit results as JSON.

--recursive and --glob are mutually exclusive. At least one path or --glob is required; dvs get with neither is a usage error.

get exposes a short -g for --glob; add only has the long --glob.

🔗Setup

Add three files, then delete them so get has something to restore.

options(width = 1000)
library(here)
proj    <- here::here(basename(tempfile(fileext = "_project")))
storage <- here::here(basename(tempfile(fileext = "_storage")))
dir.create(proj)
dir.create(storage)
dir.create(file.path(proj, "data", "sub"), recursive = TRUE)
write.csv(mtcars[1:8, ],   file.path(proj, "data", "f1.csv"))
write.csv(mtcars[9:16, ],  file.path(proj, "data", "f2.csv"))
write.csv(iris[1:10, ],    file.path(proj, "data", "sub", "f3.csv"), row.names = FALSE)
Sys.setenv(DVS_PROJECT = proj, DVS_STORAGE = storage)
cd "$DVS_PROJECT"
dvs init "$DVS_STORAGE" >/dev/null
dvs add data/f1.csv data/f2.csv data/sub/f3.csv >/dev/null
rm data/f1.csv data/f2.csv data/sub/f3.csv
dvs status --absent
+-----------------+--------+-------+
| path            | status | size  |
+-----------------+--------+-------+
| data/f1.csv     | absent | 488 B |
+-----------------+--------+-------+
| data/f2.csv     | absent | 500 B |
+-----------------+--------+-------+
| data/sub/f3.csv | absent | 312 B |
+-----------------+--------+-------+

🔗Paths

Restore a single file. Output lists each retrieved file and a total.

cd "$DVS_PROJECT"
dvs get data/f1.csv
data/f1.csv [488 B]
Total: 1 files, 488 B

After get, the file is current again.

cd "$DVS_PROJECT"
dvs status data/f1.csv
+-------------+---------+-------+
| path        | status  | size  |
+-------------+---------+-------+
| data/f1.csv | current | 488 B |
+-------------+---------+-------+

🔗-g, --glob

Restore by glob. Use ** to cross directory boundaries.

cd "$DVS_PROJECT"
dvs get -g "data/**/*.csv"
data/f2.csv [500 B]
data/sub/f3.csv [312 B]
Total: 2 files, 812 B

🔗-r, --recursive

A directory argument retrieves only the files directly in it. Here the nested data/sub/f3.csv is left alone.

cd "$DVS_PROJECT"
rm data/f1.csv data/f2.csv data/sub/f3.csv
dvs get data
dvs status --absent
data/f1.csv [488 B]
data/f2.csv [500 B]
Total: 2 files, 988 B
+-----------------+--------+-------+
| path            | status | size  |
+-----------------+--------+-------+
| data/sub/f3.csv | absent | 312 B |
+-----------------+--------+-------+

With -r the rest of the subtree is retrieved.

cd "$DVS_PROJECT"
dvs get data -r
data/sub/f3.csv [312 B]
Total: 1 files, 312 B

🔗Restore the whole project

get needs at least one path or a --glob, so there is no bare dvs get that means "everything". Pass the project root as a recursive directory instead: from the root, dvs get . -r restores every tracked file. A directory argument is resolved from where you run it, so the same command in a subdirectory restores only that subtree.

cd "$DVS_PROJECT"
rm data/f1.csv data/f2.csv data/sub/f3.csv
dvs get . -r
data/f1.csv [488 B]
data/f2.csv [500 B]
data/sub/f3.csv [312 B]
Total: 3 files, 1.3 KB

dvs get -g '**/*' does the same thing through the glob surface. Quote the pattern so the shell does not expand it first.

🔗--dry-run

Report what would be retrieved without writing files.

cd "$DVS_PROJECT"
rm data/f2.csv
dvs get data/f2.csv --dry-run
data/f2.csv [500 B]
Total: 1 files, 500 B

The file is still absent after a dry run:

cd "$DVS_PROJECT"
dvs status --absent
+-------------+--------+-------+
| path        | status | size  |
+-------------+--------+-------+
| data/f2.csv | absent | 500 B |
+-------------+--------+-------+

🔗--threads

Override the auto-detected thread count for this command.

cd "$DVS_PROJECT"
dvs get data/f2.csv --threads 2
data/f2.csv [500 B]
Total: 1 files, 500 B

🔗--json

Each result row carries path, outcome (copied or present), and size.

cd "$DVS_PROJECT"
dvs get data/f1.csv --json
[{"path":"data/f1.csv","outcome":"present","size":488}]

🔗Differences from R

The R function is dvs_get(). It returns a data frame rather than printed lines, has no --threads or --json, and shows a progress bar only in interactive sessions.

🔗See also