Skip to content

list: add --sort-by=SPEC, fixes #9009 - #10089

Merged
ThomasWaldmann merged 8 commits into
borgbackup:masterfrom
ThomasWaldmann:list-sortby-9009
Aug 12, 2026
Merged

list: add --sort-by=SPEC, fixes #9009#10089
ThomasWaldmann merged 8 commits into
borgbackup:masterfrom
ThomasWaldmann:list-sortby-9009

Conversation

@ThomasWaldmann

Copy link
Copy Markdown
Member

Adds borg list --sort-by=SPEC for archive contents, as requested in #9009.

SPEC is a comma-separated list of fields, each optionally prefixed with > for descending or < for ascending (the default) order. The sorts are applied stably from the last field to the first, so the first field is the primary criterion:

$ borg list --sort-by='>size,path' --format='{size:8d} {path}{NL}' ARCHIVE

Supported fields: path, type, mode, user, uid, group, gid, size, mtime, ctime, atime.

Without --sort-by, items are streamed as before and their order stays undefined (no tie-breaker is applied).

Notes on the implementation

  • The sort keys are the same values --format would print, so the order always matches the visible column: type / mode sort by the rendered stat.filemode() values, atime / ctime fall back to mtime if not stored, user / group fall back to the numeric id if the name is unknown.
  • No birthtime field, as there is no {birthtime} format key either. Could be added later, together with the format key.
  • Sorting needs all (matching) items in memory. That is documented in the epilog, including the hint to use borg list --format ... | sort if that is a problem. Note that the patterns and --depth filter before sorting, so only matching items are buffered.
  • Spec parsing/validation and the stable multi-field sort now live in a small new leaf module helpers/sorting.py. borg diff --sort-by was converted to it, with no change to its accepted fields, error messages or resulting order (its existing tests pass unchanged).
  • list --sort-by and diff --sort-by now have shell completion for their fields (diff --sort-by had none so far). As there are 3 different sets of sort keys now (archives / items / item diffs), the completion helper is generated once per key set from one template per shell. In tcsh, completion rules match by option name only, over all subcommands, so there one helper offers the union of all sort keys - noted in the borg completion docs.
  • Completion of the < / > prefix is not implemented: both characters are in bash's default COMP_WORDBREAKS, so the fragment never reaches the completion helper intact, and changing COMP_WORDBREAKS for them would break redirection completion for all other commands.

The last commit ("diff: --sort-by can only be given once") is the only behaviour change to diff: it adds action=Highlander, like list --sort-by, repo-list --sort-by and diff --format have. Easy to drop if unwanted.

Spec parsing/validation and the stable, direction-aware multi-field sort of
"--sort-by SPEC" options, so that commands only have to provide the sort key
extraction for their own fields.
The sort spec parsing/validation and the sorting itself now come from
helpers.sorting, only the sort key extraction stays here. The validator is a
module level object now, so shell completion can be attached to it.
SPEC is a comma-separated list of fields, each optionally prefixed with ">"
for descending or "<" for ascending (the default) order. The sorts are
applied stably from the last field to the first, thus the first field is the
primary sort criterion, e.g.: borg list --sort-by='>size,path' ARCHIVE

Sorting needs all (matching) items in memory, so without --sort-by, the items
are still streamed and their order stays undefined.
There are 3 kinds of --sort-by now (archives, items, item diffs), each with
its own set of valid sort keys, so the completion helper is generated once per
key set from one template per shell. diff --sort-by had no completion at all
before.

tcsh matches completion rules by option name only, in one flat namespace for
all subcommands, so there it stays one helper offering the union of all keys.
Like list --sort-by, repo-list --sort-by and diff --format.
@ThomasWaldmann ThomasWaldmann added this to the 2.0.0b23 milestone Aug 12, 2026
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.56098% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.82%. Comparing base (bf6a449) to head (46cfdd8).
⚠️ Report is 5 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/borg/archiver/list_cmd.py 91.66% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10089      +/-   ##
==========================================
+ Coverage   86.77%   86.82%   +0.05%     
==========================================
  Files          98       99       +1     
  Lines       17277    17324      +47     
  Branches     2622     2627       +5     
==========================================
+ Hits        14992    15042      +50     
+ Misses       1587     1586       -1     
+ Partials      698      696       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

On Windows the captured output has CRLF line endings, so assertions anchored
on "\n" did not match. Match on lines instead.
@ThomasWaldmann ThomasWaldmann self-assigned this Aug 12, 2026
@ThomasWaldmann
ThomasWaldmann merged commit 766f6a1 into borgbackup:master Aug 12, 2026
20 checks passed
@ThomasWaldmann
ThomasWaldmann deleted the list-sortby-9009 branch August 12, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant