Repository: borgbackup/borg

Issue:
recreate: drop the "experimental feature" warning?
<!--
Thank you for reporting an issue.

*IMPORTANT* -  *before* creating a new issue please look around:
 - Borgbackup documentation: http://borgbackup.readthedocs.io/en/stable/index.html
 - FAQ: https://borgbackup.readthedocs.io/en/stable/faq.html
 and
 - open issues in Github tracker: https://github.com/borgbackup/borg/issues
  
If you cannot find a similar problem, then create a new issue.

Please fill in as much of the template as possible.
-->

## Have you checked borgbackup docs, FAQ, and open Github issues?

Yes

## Is this a BUG / ISSUE report or a QUESTION?

More of a feature request, really :)

## System information. For client/server mode post info for both machines.

#### Your borg version (borg -V).

```
backup ~ # borg -V
borg 1.1.9
```

#### Operating system (distribution) and version.

```
backup ~ # lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 10 (buster)
Release:        10
Codename:       buster
backup ~ # cat /etc/debian_version
10.3
```

#### Full borg commandline that lead to the problem (leave away excludes and passwords)

```
borg recreate --dry-run --verbose --list -e 'pp:home/some.user' '::archive...'
```

## Describe the problem you're observing.

`borg recreate` currently prints a warning indicating that the `recreate` feature is still experimental:

```
recreate is an experimental feature.
Type 'YES' if you understand this and want to continue:
```

[This warning has been in the code for 4 years](https://github.com/borgbackup/borg/blame/08a12cc40523b58bdfe92be9e9d937179287e805/src/borg/archiver.py#L1569) (which was the point where `recreate` was originally implemented). As far as I can tell from the currently open bug reports, there are currently no serious issues regarding `recreate`, and looking at the closed pull requests, most of the work on it happened back in 2017.

Is this warning still relevant today, or can it safely be removed?


Discussion:
You're right, it is not new nor there is ongoing work on it currently.

But we had users who erased lots of data by wrongly using it.

We already have documented that problem, but I guess we need to replace the "experimental" warning with a "potentially dangerous" warning. Same applies to `borg check` btw.


Afaik the "erased lots of data" problems were issues related to how Borg handles patterns (absolute-relative conversion and all that) leading to unintentionally not matching any files (much like `borg extract ... /home/foo`), I feel like there is an opportunity to improve this in general. For example, borg could detect the use of absolute paths when referring to archive contents and reject or possibly patch them with a warning.

Resolving patch:
diff --git a/src/borg/archiver.py b/src/borg/archiver.py
--- a/src/borg/archiver.py
+++ b/src/borg/archiver.py
@@ -323,8 +323,10 @@ def do_init(self, args, repository):
     def do_check(self, args, repository):
         """Check repository consistency"""
         if args.repair:
-            msg = ("'check --repair' is an experimental feature that might result in data loss." +
-                   "\n" +
+            msg = ("This is a potentially dangerous function.\n"
+                   "check --repair might lead to data loss (for kinds of corruption it is not\n"
+                   "capable of dealing with). BE VERY CAREFUL!\n"
+                   "\n"
                    "Type 'YES' if you understand this and want to continue: ")
             if not yes(msg, false_msg="Aborting.", invalid_msg="Invalid answer, aborting.",
                        truish=('YES', ), retry=False,
@@ -1708,12 +1710,6 @@ def do_upgrade(self, args, repository, manifest=None, key=None):
     @with_repository(cache=True, exclusive=True, compatibility=(Manifest.Operation.CHECK,))
     def do_recreate(self, args, repository, manifest, key, cache):
         """Re-create archives"""
-        msg = ("recreate is an experimental feature.\n"
-               "Type 'YES' if you understand this and want to continue: ")
-        if not yes(msg, false_msg="Aborting.", truish=('YES',),
-                   env_var_override='BORG_RECREATE_I_KNOW_WHAT_I_AM_DOING'):
-            return EXIT_ERROR
-
         matcher = self.build_matcher(args.patterns, args.paths)
         self.output_list = args.output_list
         self.output_filter = args.output_filter
@@ -3047,6 +3043,9 @@ def define_archive_filters_group(subparser, *, sort_by=True, first_last=True):
         check_epilog = process_epilog("""
         The check command verifies the consistency of a repository and the corresponding archives.
 
+        check --repair is a potentially dangerous function and might lead to data loss
+        (for kinds of corruption it is not capable of dealing with). BE VERY CAREFUL!
+
         First, the underlying repository data files are checked:
 
         - For all segments, the segment magic header is checked.
@@ -3949,7 +3948,8 @@ def define_archive_filters_group(subparser, *, sort_by=True, first_last=True):
         recreate_epilog = process_epilog("""
         Recreate the contents of existing archives.
 
-        This is an *experimental* feature. Do *not* use this on your only backup.
+        recreate is a potentially dangerous function and might lead to data loss
+        (if used wrongly). BE VERY CAREFUL!
 
         ``--exclude``, ``--exclude-from``, ``--exclude-if-present``, ``--keep-exclude-tags``
         and PATH have the exact same semantics as in "borg create", but they only check
diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py
--- a/src/borg/testsuite/archiver.py
+++ b/src/borg/testsuite/archiver.py
@@ -252,7 +252,6 @@ class ArchiverTestCaseBase(BaseTestCase):
     def setUp(self):
         os.environ['BORG_CHECK_I_KNOW_WHAT_I_AM_DOING'] = 'YES'
         os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'YES'
-        os.environ['BORG_RECREATE_I_KNOW_WHAT_I_AM_DOING'] = 'YES'
         os.environ['BORG_PASSPHRASE'] = 'waytooeasyonlyfortests'
         self.archiver = not self.FORK_DEFAULT and Archiver() or None
         self.tmpdir = tempfile.mkdtemp()


Test patch: