Skip to content

tag options: one tag per option, fixes #10430 - #10432

Merged
ThomasWaldmann merged 7 commits into
borgbackup:masterfrom
ThomasWaldmann:tag-append-10430
Sep 26, 2026
Merged

ThomasWaldmann merged 7 commits into
borgbackup:masterfrom
ThomasWaldmann:tag-append-10430

Conversation

@ThomasWaldmann

Copy link
Copy Markdown
Member

Fixes #10430.

borg tag --set/--add/--remove and borg create --tags took multiple tags per option (nargs="*" / nargs="+"), so they swallowed the archive NAME if it came after them, e.g. borg tag --set keep aid:1ddaae55 failed with a confusing error.

Changes

  • tag: --set, --add and --remove take exactly one tag and can be given multiple times, e.g. borg tag --add a --add b NAME. Also added examples to borg tag --help.
  • tag: new --clear removes all normal tags, but keeps special tags like @PROT. It can be combined with --add to replace the normal tags and is mutually exclusive with --set. This replaces the previous way of clearing tags with a bare --set, which is not possible anymore.
  • create: --tags is replaced by --tag, taking one tag per option, e.g. borg create --tag foo --tag bar NAME PATH.
  • tag: refuse to change the tags of all archives without an explicit selection (NAME or archive filters), like borg delete does. Use -a 'sh:*' to change all archives. Just showing the tags of all archives still works without a selection.
  • tag: warn (rc 1) if --set is refused because it would remove pre-existing special tags. Previously this was silent and returned rc 0.
  • docs: explain that the tags: match pattern takes a comma-separated list and matches archives having all of the given tags.

Implementation note

The repeatable options use action="extend", nargs=1 rather than action="append": jsonargparse re-validates parsed values after parsing and, for nargs=None, calls the type on the whole appended list, which breaks the tag validator. With extend + nargs=1, it gets a flat list and checks each element; keeping type=tag_validator also keeps shell completion for tags working.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.73684% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 88.65%. Comparing base (925c55f) to head (cce5c99).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/borg/archiver/tag_cmd.py 94.73% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10432      +/-   ##
==========================================
+ Coverage   88.63%   88.65%   +0.01%     
==========================================
  Files         103      103              
  Lines       19206    19217      +11     
  Branches     2990     2993       +3     
==========================================
+ Hits        17024    17036      +12     
+ Misses       1516     1513       -3     
- Partials      666      668       +2     

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

ThomasWaldmann added a commit to borgbackup/borgstore that referenced this pull request Sep 25, 2026
Path.rename() replaces an existing destination on POSIX, but raises
FileExistsError on Windows. Use Path.replace() so move() behaves the same
everywhere and like the other backends, which all overwrite the target.

This broke e.g. soft-deleting an item while a soft-deleted item of the
same name already existed (borgbackup/borg#10432 CI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ThomasWaldmann ThomasWaldmann added this to the 2.0.0b25 milestone Sep 26, 2026
ThomasWaldmann and others added 7 commits September 26, 2026 23:19
…0430

They used nargs="*" and thus swallowed the archive NAME if it was given
after them, e.g. "borg tag --set keep aid:1ddaae55" failed.

Now each option takes exactly one tag and can be given multiple times,
e.g. "borg tag --add a --add b NAME".

Also add examples to the "borg tag" help.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Special tags like @prot are kept. --clear can be combined with --add
to replace the normal tags, it is mutually exclusive with --set.

Previously, a bare "--set" cleared all tags, but that is not possible
anymore since --set now takes exactly one tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--tags used nargs="+" and thus swallowed the archive NAME if it was given
after it, e.g. "borg create --tags foo NAME PATH" failed.

Now --tag takes exactly one tag and can be given multiple times,
e.g. "borg create --tag foo --tag bar NAME PATH".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without NAME or archive filter options, "borg tag --set/--clear/--add/--remove"
silently changed the tags of all archives in the repository.

Now it aborts like "borg delete" does, unless archives are selected
explicitly, e.g. using -a 'sh:*' for all archives. Just showing the
tags of all archives still works without a selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Previously, borg silently did not set the tags, so it looked like the
given tags were just ignored, and the return code was 0.

Now borg emits a warning naming the special tags that would be removed
and exits with rc 1 (warning).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document that tags: takes a comma-separated list of tags and matches
archives having all of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Previously, "borg tag" always rewrote the archive metadata (and thus the
archive entry in the repository), even when just listing the tags or when
the requested change was a no-op (including a refused --set).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ThomasWaldmann
ThomasWaldmann merged commit e6803d2 into borgbackup:master Sep 26, 2026
25 checks passed
@ThomasWaldmann
ThomasWaldmann deleted the tag-append-10430 branch September 26, 2026 22:09
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.

tag: --set/--add/--remove swallow the archive argument

1 participant