Recent changes to this wiki:

TODO for export --json* options
diff --git a/doc/todo/export_--json_--json-progress_--json-error-messages.mdwn b/doc/todo/export_--json_--json-progress_--json-error-messages.mdwn
new file mode 100644
index 000000000..c44d1be52
--- /dev/null
+++ b/doc/todo/export_--json_--json-progress_--json-error-messages.mdwn
@@ -0,0 +1,4 @@
+Pretty much to mimic `copy` in terms of its interfaceability with external commands.
+
+[[!meta author=yoh]]
+[[!tag projects/datalad]]

Added a comment
diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_5_7829d524f435dc908149f29a53e3a1ab._comment b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_5_7829d524f435dc908149f29a53e3a1ab._comment
new file mode 100644
index 000000000..89ada2b9e
--- /dev/null
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_5_7829d524f435dc908149f29a53e3a1ab._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="braun.markus89@51b521a42cc994db864df308627bd6454f9c309d"
+ nickname="braun.markus89"
+ avatar="http://cdn.libravatar.org/avatar/c11d06a0d9db6a9472b05ee01c342ca4"
+ subject="comment 5"
+ date="2020-05-25T11:07:07Z"
+ content="""
+so, thank you once again, Joey, in particular for this great tool ;-)
+"""]]

Added a comment
diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_4_8a43d4e00c6b48999fe84d2f7ad55877._comment b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_4_8a43d4e00c6b48999fe84d2f7ad55877._comment
new file mode 100644
index 000000000..b405fe385
--- /dev/null
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_4_8a43d4e00c6b48999fe84d2f7ad55877._comment
@@ -0,0 +1,25 @@
+[[!comment format=mdwn
+ username="braun.markus89@51b521a42cc994db864df308627bd6454f9c309d"
+ nickname="braun.markus89"
+ avatar="http://cdn.libravatar.org/avatar/c11d06a0d9db6a9472b05ee01c342ca4"
+ subject="comment 4"
+ date="2020-05-25T11:06:05Z"
+ content="""
+git version is 2.26.1, so this should be fine.
+
+I guess, git-annex couldn't do it any better, still git tries to overallocate memory.
+My Synology NAS only got 1gb of memory (at least 600mb are used all the time), so I wonder why \"hanging up\" the pipe works when unlocking 1gb file but not for 2gb. But the Synology linux is a little bit weird, so I have to give up on debugging there. The 1gb memory spec of my NAS is ridiculously low (maybe too low for git anyways) and cannot be upgraded....
+
+For the sake of documentation for other synology users with a low-spec NAS
+
+Workaround that did work
+
+* create a user with uid/gid matching the NAS user and mount via NFSv3. On the client system the memory is sufficient to run every git-annex command.
+
+Workarounds that did not work out
+
+* NFSv4 with idmapping (configuring the Kerberos authentication would have taken a lot of time and not even sure if it would have worked out in the end)
+* SSHFS (the sshfs server provided by Synology seems to be broken, resulting in broken symlinks on my linux client system -> which is obviously a no go for git annex ;-) )
+
+
+"""]]

Tried --preserve-filename with a torrent, didn't work
diff --git a/doc/bugs/addurl_--preserve-filename_still_modifies_file_names.mdwn b/doc/bugs/addurl_--preserve-filename_still_modifies_file_names.mdwn
new file mode 100644
index 000000000..80445ab6a
--- /dev/null
+++ b/doc/bugs/addurl_--preserve-filename_still_modifies_file_names.mdwn
@@ -0,0 +1,41 @@
+### Please describe the problem.
+
+The new `--preserve-filename` option does not have its described effect on torrent files.
+
+### What steps will reproduce the problem?
+
+[[!format sh """
+$ git annex addurl --preserve-filename \
+        http://downloads.endor.at/chaos-math_multi-language_1080p_mkv.ea15601881aa1be1.torrent
+"""]]
+
+(cancelling when at least a file has arrived)
+
+[[!format sh """
+$ tree
+└── downloads.endor.at_chaos-math_multi-language_1080p_mkv.ea15601881aa1be1.torrent/
+    └── 01._Motion_and_determinism_-_Panta_Rhei__1080p_.mkv 
+$ btcheck -l <(curl 'https://downloads.endor.at/chaos-math_multi-language_1080p_mkv.ea15601881aa1be1.torrent')
+Base directory : chaos-math_multi-language_1080p_mkv
+01. Motion and determinism - Panta Rhei [1080p].mkv     (409315188)
+"""]]
+
+Based on the description of `--preserve-filename`, given that nothing in the names is particularly malicious, I'd have expected the tree output to look like this:
+
+[[!format sh """
+$ tree
+└── chaos-math_multi-language_1080p_mkv/   (as per base directory)
+    └── 01. Motion and determinism - Panta Rhei [1080p].mkv 
+"""]]
+
+### What version of git-annex are you using? On what operating system?
+
+8.20200522 (built using `gbp buildpackage` from current git master, 87dc9cd0)
+
+### Please provide any additional information below.
+
+This option, when working with torrents, would be a building block to [[todo/bittorrent: support offline operation and verification]], and resolve most of the suggestions from there.
+
+### Have you had any luck using git-annex before?
+
+Yes: It saved me from potential data loss when my backup cron jobs stopped working and the mails got lost -- `git annex drop` failing on the laptops was both the right thing to do given numcopies=2, and alerted me to the problem in due time.

add news item for git-annex 8.20200522
diff --git a/doc/news/version_8.20200226.mdwn b/doc/news/version_8.20200226.mdwn
deleted file mode 100644
index 210e63594..000000000
--- a/doc/news/version_8.20200226.mdwn
+++ /dev/null
@@ -1,56 +0,0 @@
-News for git-annex 8.20200226:
-
-   This version of git-annex uses repository version 8 for all repositories.
-   Existing repositories will be automatically upgraded by default.
-   You can prevent this, by runing: git config annex.autoupgraderepository false
-   The upgrade process involves regenerating some sqlite databases. There are a
-   couple consequences of the upgrade to keep in mind:
-
-   * Any incremental fscks that were started in v7 won't resume where
-     they left off in v8, but will instead begin again from the first file.
-
-   * An interrupted export that was started in v7 won't resume where it left
-     off after upgrade to v8; files will be re-uploaded to the export remote.
-
-   * After the upgrade, git-annex will in some situations have to do extra
-     work while it finishes populating its sqlite databases.
-
-   Also, there are some behavior changes around adding dotfiles. While before
-   git-annex add skipped adding dotfiles when operating on whole directories,
-   and added dotfiles that were explicitly listed to the annex, it now adds
-   dotfiles to git by default, unless annex.dotfiles is set to true.
-
-git-annex 8.20200226 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * New v8 repository version.
-   * v7 upgrades automatically to v8. The upgrade deletes old sqlite
-     databases, which may cause git-annex to need to do extra work to
-     regenerate the databases or due to not having the information from the
-     old databases available. Two notable cases are interrupted incremental
-     fscks and interrupted exports, both of which will restart from the
-     beginning.
-   * Improved serialization of filenames and keys to the sqlite databases,
-     avoiding encoding problems and speeding up operations on them.
-   * Add some missing indexes to sqlite databases. This will speed up
-     some things involving export and import remotes, and git-annex smudge.
-     Microbenchmarks show around 10-25% speedup of sqlite database operations.
-   * add: When adding a whole directory, any dotfiles found in it will
-     not be skipped, but will be added to git by default. This behavior
-     can be configured with annex.dotfiles.
-   * add: Removed special case for explicitly passing dotfiles,
-     that no longer adds them to the annex, but to git. This behavior
-     can be configured with annex.dotfiles.
-   * add: Removed the --include-dotfiles option.
-   * initremote, enableremote: Set remote.name.skipFetchAll when
-     the remote cannot be fetched from by git, so git fetch --all
-     will not try to use it.
-   * Fix some cases where handling of keys with extensions varied depending
-     on the locale.
-   * annex.maxextensionlength used to be the number of characters, not
-     bytes, when in a utf-8 locale. It's now always the number of bytes.
-   * Extended annex.security.allowed-ip-addresses to let specific ports
-     of an IP address to be used, while denying use of other ports.
-   * init --version: When the version given is one that automatically
-     upgrades to a newer version, use the newer version instead.
-   * Auto upgrades from older repo versions, like v5, now jump right to v8.
-   * Makefile: Support newer versions of cabal that use the new-build system."""]]
diff --git a/doc/news/version_8.20200522.mdwn b/doc/news/version_8.20200522.mdwn
new file mode 100644
index 000000000..285bb3879
--- /dev/null
+++ b/doc/news/version_8.20200522.mdwn
@@ -0,0 +1,34 @@
+git-annex 8.20200522 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Fix bug that made enableremote of S3 and webdav remotes, that
+     have embedcreds=yes, fail to set up the embedded creds, so accessing
+     the remotes failed. (Regression introduced in version 7.20200202.7)
+   * addurl, importfeed: Avoid adding filenames with leading '.', instead
+     it will be replaced with '\_'.
+   * addurl, importfeed: Allow '-' in filenames, as long as it's not the
+     first character.
+   * addurl --preserve-filename: New option, uses server-provided filename
+     without any sanitization, but will fail if the filename has an obvious
+     security problem like using an escape sequence or trying to escape
+     the current directory.
+   * whereis: Added --format option.
+   * S3: Support signature=v4, to use S3 Signature Version 4.
+     Some S3 services seem to require v4, while others may only
+     support v2, which remains the default.
+   * upgrade: When upgrade fails due to an exception, display it.
+   * repair: Improve fetching from a remote with an url in host:path format.
+   * git-lfs repos that encrypt the annexed content but not the git repo
+     only need --force passed to initremote, allow enableremote and
+     autoenable of such remotes without forcing again.
+   * When accessing a remote fails, always display a reason why.
+   * Display a warning message when a remote uses a protocol, such as
+     git://, that git-annex does not support. Silently skipping such a
+     remote was confusing behavior.
+   * Also display a warning message when a remote, without a known uuid,
+     is located in a directory that does not currently exist, to avoid
+     silently skipping such a remote.
+   * sync: Avoid an ugly error message when nothing has been committed to
+     master yet and there is a synced master branch to merge from.
+   * Display a warning message when asked to operate on a file inside a
+     directory that's a symbolic link to elsewhere.
+   * Support building with tasty-1.3."""]]
\ No newline at end of file

Added a comment: git-annex get fails
diff --git a/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients/comment_2_f1de80703cd0f1c15d5cf17f763adc9d._comment b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients/comment_2_f1de80703cd0f1c15d5cf17f763adc9d._comment
new file mode 100644
index 000000000..51b5bc1ca
--- /dev/null
+++ b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients/comment_2_f1de80703cd0f1c15d5cf17f763adc9d._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="arseni.lapunov@34f437c25a6a8c6d317dce0bb7c5b44d568fa595"
+ nickname="arseni.lapunov"
+ avatar="http://cdn.libravatar.org/avatar/ccbdceb84c46bf9af5f9162bbf982f0b"
+ subject="git-annex get fails"
+ date="2020-05-22T14:28:23Z"
+ content="""
+Thank you! Exactly git annex get failure was an actual problem, but I thought that it should not succeed without cached creds.
+
+Regards
+"""]]

Added a comment
diff --git a/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_4_577f586843c1d7e54d115796988f912d._comment b/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_4_577f586843c1d7e54d115796988f912d._comment
new file mode 100644
index 000000000..3200ca1da
--- /dev/null
+++ b/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_4_577f586843c1d7e54d115796988f912d._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="basile.pinsard@f1a7fae9f3bd9d5282fca11f62ad53b45a8eb317"
+ nickname="basile.pinsard"
+ avatar="http://cdn.libravatar.org/avatar/87e1f73acf277ad0337b90fc0253c62e"
+ subject="comment 4"
+ date="2020-05-22T13:24:19Z"
+ content="""
+Thanks for the detailed answer.
+
+So the only way to revert metadata changes is to reset the git-annex branch to a previous commit with `git update-ref refs/heads/git-annex <commit>`. 
+
+Thanks for the `git-log --stat` tip.
+
+I guess I could get an approximate match between the master and git-annex branches commits based on commit date.
+"""]]

diff --git a/doc/bugs/separate-git-dir_OK_under_Linux_FAIL_under_Windows.mdwn b/doc/bugs/separate-git-dir_OK_under_Linux_FAIL_under_Windows.mdwn
new file mode 100644
index 000000000..58c757f4f
--- /dev/null
+++ b/doc/bugs/separate-git-dir_OK_under_Linux_FAIL_under_Windows.mdwn
@@ -0,0 +1,180 @@
+### Please describe the problem.
+
+When a git-annex is cloned from one where git init was run with --separate-git-dir, it works fine under Linux, but fails under Windows
+
+[[!format sh """
+shaddy@JAZZ2-W10 C:\slaveproj
+> git annex get services
+get services
+  Unable to access these remotes: origin
+
+  Try making some of these repositories available:
+        615bdcd5-6a5e-4330-84a2-b6c30cb3e5e4 -- shaddy@jazz2-w10:C:\masterproj [origin]
+failed
+git-annex: get: 1 failed
+
+"""]]
+
+### What steps will reproduce the problem?
+
+[[!format sh """
+shaddy@JAZZ2-W10 C:\
+> git init --separate-git-dir masterproj.git masterproj
+Initialized empty Git repository in C:/masterproj.git/
+
+shaddy@JAZZ2-W10 C:\
+> cd masterproj
+
+shaddy@JAZZ2-W10 C:\masterproj
+> git annex init
+init
+  Detected a filesystem without fifo support.
+
+  Disabling ssh connection caching.
+
+  Detected a crippled filesystem.
+(scanning for unlocked files...)
+
+  Entering an adjusted branch where files are unlocked as this filesystem does not support locked files.
+
+Switched to branch 'adjusted/master(unlocked)'
+ok
+(recording state in git...)
+
+shaddy@JAZZ2-W10 C:\masterproj
+> copy c:\Windows\System32\drivers\etc\services .
+        1 file(s) copied.
+
+shaddy@JAZZ2-W10 C:\masterproj
+> git annex add services
+add services
+ok
+(recording state in git...)
+
+shaddy@JAZZ2-W10 C:\masterproj
+> git commit -m services
+[adjusted/master(unlocked) e9d5e15] services
+ 1 file changed, 1 insertion(+)
+ create mode 100644 services
+
+shaddy@JAZZ2-W10 C:\masterproj
+> cd \
+
+shaddy@JAZZ2-W10 C:\
+> git clone masterproj slaveproj
+Cloning into 'slaveproj'...
+done.
+
+shaddy@JAZZ2-W10 C:\
+> cd slaveproj
+
+shaddy@JAZZ2-W10 C:\slaveproj
+> git annex init
+init
+  Detected a filesystem without fifo support.
+
+  Disabling ssh connection caching.
+
+  Detected a crippled filesystem.
+(merging origin/git-annex into git-annex...)
+(recording state in git...)
+(scanning for unlocked files...)
+ok
+(recording state in git...)
+
+shaddy@JAZZ2-W10 C:\slaveproj
+> dir
+ Volume in drive C has no label.
+ Volume Serial Number is DE6E-211A
+
+ Directory of C:\slaveproj
+
+22/05/2020  08:57 PM    <DIR>          .
+22/05/2020  08:57 PM    <DIR>          ..
+22/05/2020  08:57 PM                97 services
+               1 File(s)             97 bytes
+               2 Dir(s)  24,926,748,672 bytes free
+
+shaddy@JAZZ2-W10 C:\slaveproj
+> type services
+/annex/objects/SHA256E-s17463--b26309dfd89a9cc94481536b4d662941429df79873bb59620f53db939ff5ec29
+
+shaddy@JAZZ2-W10 C:\slaveproj
+> git annex get services
+get services
+  Unable to access these remotes: origin
+
+  Try making some of these repositories available:
+        615bdcd5-6a5e-4330-84a2-b6c30cb3e5e4 -- shaddy@jazz2-w10:C:\masterproj [origin]
+failed
+git-annex: get: 1 failed
+
+shaddy@JAZZ2-W10 C:\slaveproj
+>
+"""]]
+
+### What version of git-annex are you using? On what operating system?
+
+[[!format sh """
+shaddy@JAZZ2-W10 C:\slaveproj
+> git annex version
+git-annex version: 8.20200330-g971791563
+build flags: Assistant Webapp Pairing S3 WebDAV TorrentParser Feeds Testsuite
+dependency versions: aws-0.21.1 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.4 feed-1.2.0.1 ghc-8.6.5 http-client-0.6.4 persistent-sqlite-2.9.3 torrent-10000.1.1 uuid-1.3.13 yesod-1.6.0.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs hook external
+operating system: mingw32 x86_64
+supported repository versions: 8
+upgrade supported from repository versions: 2 3 4 5 6 7
+local repository version: 8
+"""]]
+
+### Please provide any additional information below.
+
+Works fine under Linux:
+
+[[!format sh """
+shaddy@jazz-debian:~$ git init --separate-git-dir /var/tmp/masterproj.git masterproj
+Initialized empty Git repository in /var/tmp/masterproj.git/
+shaddy@jazz-debian:~$ for d in masterproj/ /var/tmp/masterproj.git/; do stat -f $d | head -2; done
+  File: "masterproj/"
+    ID: 4efe0be616b5a688 Namelen: 255     Type: ext2/ext3
+  File: "/var/tmp/masterproj.git/"
+    ID: 6736efe4caec433 Namelen: 255     Type: ext2/ext3
+shaddy@jazz-debian:~$ cd masterproj/
+shaddy@jazz-debian:~/masterproj$ git annex init
+init  ok
+(recording state in git...)
+shaddy@jazz-debian:~/masterproj$ cp /etc/services .
+shaddy@jazz-debian:~/masterproj$ git annex add services
+add services ok
+(recording state in git...)
+shaddy@jazz-debian:~/masterproj$ git commit -m services
+[master (root-commit) a42f63a] services
+ 1 file changed, 1 insertion(+)
+ create mode 120000 services
+shaddy@jazz-debian:~/masterproj$ cd ~/
+shaddy@jazz-debian:~$ git clone masterproj/ slaveproj/
+Cloning into 'slaveproj'...
+done.
+shaddy@jazz-debian:~$ cd slaveproj/
+shaddy@jazz-debian:~/slaveproj$ git annex init
+init  (merging origin/git-annex into git-annex...)
+(recording state in git...)
+ok
+(recording state in git...)
+shaddy@jazz-debian:~/slaveproj$ ls -lL services
+ls: cannot access 'services': No such file or directory
+shaddy@jazz-debian:~/slaveproj$ git annex get services
+get services (from origin...)
+SHA256E-s18774--60ef85f14cd630692bf91756e2e81351c54e2eace0310188eb4f6af4d9858c91
+         18,774 100%    0.00kB/s (checksum...)    0:00:00 (xfr#1, to-chk=0/1)
+ok
+(recording state in git...)
+shaddy@jazz-debian:~/slaveproj$ ls -lL services
+-r--r--r-- 1 shaddy shaddy 18774 May 22 20:53 services
+"""]]
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+
+This issue is not a show stopper. I otherwise love the concepts behind git-annex very much.

remove this post to a deleted topic
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_39_eee1859e679fca35d1c62b89e5bd0435._comment b/doc/forum/lets_discuss_git_add_behavior/comment_39_eee1859e679fca35d1c62b89e5bd0435._comment
deleted file mode 100644
index 5a1feb024..000000000
--- a/doc/forum/lets_discuss_git_add_behavior/comment_39_eee1859e679fca35d1c62b89e5bd0435._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="codelix"
- avatar="http://cdn.libravatar.org/avatar/667ff4d0387694f28236639bab0faf2c"
- subject="comment 39"
- date="2020-05-21T19:11:01Z"
- content="""
-Sorry `largefiles` already sort of does this. My main hang up might just be the name, it's not intuitive what all side effects it'll have. Having it called something explicit like `addtoannex` will probably make it super clear to me.
-
-Also what is the current default value of `annex.gitaddtoannex`? And how does this interact with largefiles as it is now?
-"""]]

response
diff --git a/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_3_71e8d6ed7b1a6088cdb5abb5667ee619._comment b/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_3_71e8d6ed7b1a6088cdb5abb5667ee619._comment
new file mode 100644
index 000000000..ee3c35d41
--- /dev/null
+++ b/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_3_71e8d6ed7b1a6088cdb5abb5667ee619._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2020-05-21T19:27:40Z"
+ content="""
+`git annex add` does not result in the smudge filter being run.
+
+You could configure git not to run the filters ever (see git docs) but then
+git-annex features involving unlocked files will of course break.
+
+Could I suggest that, in general, you wait until you have actually
+seen git-annex behave badly before worrying about it? (This is in the
+context of also having seen some other comments you made elsewhere.)
+That also lets you file concrete bug reports, rather than posting worries
+that may be ungrounded.
+"""]]

Support building with tasty-1.3
This commit was sponsored by Ethan Aubin.
diff --git a/CHANGELOG b/CHANGELOG
index 1072e9390..12a330bd2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -31,6 +31,7 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
   * Fix bug that made enableremote of S3 and webdav remotes, that
     have embedcreds=yes, fail to set up the embedded creds, so accessing
     the remotes failed. (Regression introduced in version 7.20200202.7)
+  * Support building with tasty-1.3.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Test.hs b/Test.hs
index 7f79fafdd..0873bb14e 100644
--- a/Test.hs
+++ b/Test.hs
@@ -1,6 +1,6 @@
 {- git-annex test suite
  -
- - Copyright 2010-2019 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -19,6 +19,7 @@ import Test.Tasty.Runners
 import Test.Tasty.HUnit
 import Test.Tasty.QuickCheck
 import Test.Tasty.Ingredients.Rerun
+import Test.Tasty.Options
 import Options.Applicative (switch, long, help, internal)
 
 import qualified Data.Map as M
@@ -96,7 +97,7 @@ import qualified Types.Remote
 
 optParser :: Parser TestOptions
 optParser = TestOptions
-	<$> suiteOptionParser ingredients (tests False True mempty)
+	<$> snd tastyParser
 	<*> switch
 		( long "keep-failures"
 		<> help "preserve repositories on test failure"
@@ -107,6 +108,15 @@ optParser = TestOptions
 		)
 	<*> cmdParams "non-options are for internal use only"
 
+tastyParser :: ([String], Parser Test.Tasty.Options.OptionSet)
+#if MIN_VERSION_tasty(1,3,0)
+tastyParser = go
+#else
+tastyParser = ([], go)
+#endif
+  where
+ 	go = suiteOptionParser ingredients (tests False True mempty)
+
 runner :: TestOptions -> IO ()
 runner opts
 	| fakeSsh opts = runFakeSsh (internalData opts)
@@ -118,6 +128,10 @@ runner opts
 	-- suite.
 	subenv = "GIT_ANNEX_TEST_SUBPROCESS"
 	runsubprocesstests Nothing = do
+		let warnings = fst tastyParser
+		unless (null warnings) $ do
+			hPutStrLn stderr "warnings from tasty:"
+			mapM_ (hPutStrLn stderr) warnings
 		pp <- Annex.Path.programPath
 		Utility.Env.Set.setEnv subenv "1" True
 		ps <- getArgs
diff --git a/doc/bugs/Build_failures_with_tasty_1.3.mdwn b/doc/bugs/Build_failures_with_tasty_1.3.mdwn
index e7f33f00a..0ca3c12f0 100644
--- a/doc/bugs/Build_failures_with_tasty_1.3.mdwn
+++ b/doc/bugs/Build_failures_with_tasty_1.3.mdwn
@@ -146,3 +146,4 @@ Build git-annex with tasty-1.3
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
 Yes.
 
+> [[fixed|done]] --[[Joey]] 

Added a comment
diff --git a/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_2_01e6d32c85524a23399a33b5fb12ec06._comment b/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_2_01e6d32c85524a23399a33b5fb12ec06._comment
new file mode 100644
index 000000000..8c5c668d2
--- /dev/null
+++ b/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_2_01e6d32c85524a23399a33b5fb12ec06._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="codelix"
+ avatar="http://cdn.libravatar.org/avatar/667ff4d0387694f28236639bab0faf2c"
+ subject="comment 2"
+ date="2020-05-21T19:17:55Z"
+ content="""
+Thanks for the super quick response Joey.
+
+That then sounds like `git add` and `git annex add` do get a performance impact (since they run smudge/clean which is not mandatory, or is no-op) even if I don't use unlock or adjust. Is that right? Is there a repo setting that will make it not use them?
+
+My understanding is that git pre/post commit hooks are the ones that are useful for standard symlink approach and dont need smudge/clean at all. Please correct me if I am wrong.
+
+Also, just want to say I appreciate all the effort that you do for this. I have tons of data managed with this and should probably write up that story of how I manage my files.
+"""]]

Added a comment
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_39_eee1859e679fca35d1c62b89e5bd0435._comment b/doc/forum/lets_discuss_git_add_behavior/comment_39_eee1859e679fca35d1c62b89e5bd0435._comment
new file mode 100644
index 000000000..5a1feb024
--- /dev/null
+++ b/doc/forum/lets_discuss_git_add_behavior/comment_39_eee1859e679fca35d1c62b89e5bd0435._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="codelix"
+ avatar="http://cdn.libravatar.org/avatar/667ff4d0387694f28236639bab0faf2c"
+ subject="comment 39"
+ date="2020-05-21T19:11:01Z"
+ content="""
+Sorry `largefiles` already sort of does this. My main hang up might just be the name, it's not intuitive what all side effects it'll have. Having it called something explicit like `addtoannex` will probably make it super clear to me.
+
+Also what is the current default value of `annex.gitaddtoannex`? And how does this interact with largefiles as it is now?
+"""]]

remove this thread, which has outlived its usefulness
Based on the last three comments on this thread it was going to keep
collecting complaints from people who glanced at the thread, did not
notice it was for an old, solved issue, and decided to followup.
Also, the tone of this thread, while very constructive in some places,
is very very outraged in others. This apparently leads people to feel
that randomly saying they don't trust me is a reasonable thing to post
at the end of a long thread they have not bothered to read all of, by
their own admission.
So this thread seems to have become a source of confusion for users, and
a source of pain and disincentive to worm on git-annex for me. Yes, I'm
taking the rest of today to go do something actually fun obviously.
diff --git a/doc/forum/lets_discuss_git_add_behavior.mdwn b/doc/forum/lets_discuss_git_add_behavior.mdwn
deleted file mode 100644
index 8071a2af4..000000000
--- a/doc/forum/lets_discuss_git_add_behavior.mdwn
+++ /dev/null
@@ -1,6 +0,0 @@
-With v7, the default behavior of `git add` in a git-annex repo changed
-to adding it as an annexed, unlocked file.
-
-It may be a little late to talk about this since v7 has become the default
-already, but I was asked to explain my thoughts on it, and I'm also
-interested in hearing your thoughts. --[[Joey]]
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_10_61cfc365afd97b13ac75c62304c0858a._comment b/doc/forum/lets_discuss_git_add_behavior/comment_10_61cfc365afd97b13ac75c62304c0858a._comment
deleted file mode 100644
index 5a54282ef..000000000
--- a/doc/forum/lets_discuss_git_add_behavior/comment_10_61cfc365afd97b13ac75c62304c0858a._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="Ilya_Shlyakhter"
- avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
- subject="separate annex.git-add.largefiles and annex.git-annex-add.largefiles settings"
- date="2019-10-10T18:33:50Z"
- content="""
-[[separate `annex.git-add.largefiles` and `annex.git-annex-add.largefiles` settings|todo/separate_annex.largefiles.git-add_and_annex.largefiles.git-annex-add_settings]] would let you configure `git add` to only add to git while still letting `git annex add` decide what gets annexed.
-"""]]
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_11_d7dd41721dd86ede3746e60e3b7aa2b2._comment b/doc/forum/lets_discuss_git_add_behavior/comment_11_d7dd41721dd86ede3746e60e3b7aa2b2._comment
deleted file mode 100644
index 71fac9a60..000000000
--- a/doc/forum/lets_discuss_git_add_behavior/comment_11_d7dd41721dd86ede3746e60e3b7aa2b2._comment
+++ /dev/null
@@ -1,141 +0,0 @@
-[[!comment format=mdwn
- username="amindfv@6f75355c5dad3450ed73d1f01715be90dfdd6cd6"
- nickname="amindfv"
- avatar="http://cdn.libravatar.org/avatar/9cdda587f634ea9a85b34b25be421676"
- subject="comment 11"
- date="2019-10-12T21:12:51Z"
- content="""
-First off, I love git annex and I truly appreciate all the hard work that's gone into it, so I hope you'll take my frustration as constructive when I say:
-
-Making \"git add\" mean \"git annex add\" is a **terrible** default and it should be reverted **ASAP**.
-
-## v7 is an entirely different tool than v5
-
-    mkdir foo && cd foo
-    git init && git annex init
-    echo 'one' > a.txt
-    git add a.txt
-    git commit -m '+'
-    echo 'two' >> a.txt
-    git diff
-
-I don't get a diff!! What??! Except for after \"git annex init\", git-annex has kept completely quiet (not warning me about any of this), and yet it's hijacked the whole repo.
-\"git show\" is also broken, \"git add -p\", \"git log -p\", etc etc.
-
-As others have mentioned, \"git clone\" may cause people to lose their data as well.
-
-In other words, \"git annex\" is no longer a couple of additional commands to use within git - it's something closer to a replacement of git. It feels like a takeover of my git repos.
-
-## It forces a workflow on users
-
-One of the beautiful things about git-annex is it adds a few simple concepts to git, and allows us to use those new primitives in any way we like. This has allowed users to invent lots of different workflows that meet their needs.
-
-I've seen lots of different types of repo configurations and workflows, but for discussion here I think we only need to talk about two:
-
-  1. \"Big bunch-o-binaries\" (BBOB): user wants to keep their photo collection/scientific data/etc. in a big repo and they've got some way (like the assistant) to sync it. This could be considered to be a \"dropbox replacement\". In a BBOB nobody ever wants to look at a diff between versions of a file, do line-by-line merges, or use most of the other features of git.
-
-  2. All uses that aren't that one! But let's be specific and describe a couple:
-    * I've got a repo (dozens, actually) which is just code, but somewhere along the line I had a large data file I wanted to add and didn't want to slow git down. I \"git annex init && git annex add\"ed and was done with it. Back to writing code.
-    * I've got a repo which is a true mixture of large binaries and small text files. E.g. for a video editing project I've got raw video files as well as various configuration scripts, notes, the .kdenlive file, etc.
-
-This change puts a giant wedge between use case #1 and #2.
-
-As an example, the org-mode people suggest using git-annex: <https://orgmode.org/worg/org-tutorials/index.html> . I can't imagine they'd be happy to accidentally lose the ability to get diffs between versions of their .org files.
-
-## We don't know how big of a breaking change this is...
-
-...and it may be very large.
-
-How many people use \"git add\" to mean \"git add\" in at least one of their annex repos? We don't know! Compatibility with a big breaking change like this wasn't asked in the last user survey (which I happily took part in): <https://git-annex-survey.branchable.com/polls/2018/>
-
-But we can look at what _was_ asked to try and estimate the extent of the breakage:
-
-As a proxy, we could examine how many people use the assistant (more likely to simply have a big-bunch-o-binaries), vs. number of people who use it on the command line (more likely to be carefully managing their repos, including which files are in \"vanilla\" git vs annex). The numbers in the survey indicate there are 14 people using it on the command line for every 1 person using the assistant (85% to 6%).
-
-We can also look at how many people were using any v7 features: in the most recent survey 75% of people say they're not using any v7 features, and another 7% say they don't know, which I read as not following this discussion very closely. This suggests to me most people (at least 82%) were happy using git annex basically as it was.
-
-That idea (\"we're basically happy how it is already\") is borne out by other questions: 83% of users rate themselves between \"happy\" and \"one of my favorite applications of all time\" (FWIW, I fall into the \"one of my favorie applications of all time\" camp!)
-
-In addition, the \"blocking problems,\" \"focus,\" and \"roadmap\" sections of the survey don't provide compelling evidence that changing fundamentally how git-annex interacts with git is something anyone's clamoring for.
-
-85% of people mostly use `git annex` from the command line. How many of those people have used \"git add\" in an annex repo at least once, and (now incorrectly) believe they know what it's going to do to their repo?
-
-## More broken workflows
-
-Even repos which mainly *are* BBOB (big-bunch-o-binaries) may have a README file or other files like them. I note that most (all?) repos here have text files that are in \"plain git\": <https://git-annex.branchable.com/publicrepos/>
-
-Now when I \"apt upgrade\" and add a new source file to one of my code repos, it's going to be `git-annex-add`ed? Does that mean I can't (easily, sensibly) push it to a code hosting platform (GitLab, Github)?
-
-Forcing people to this behavior by default reifies one workflow (BBOB) over all others, and basically replaces one tool (basically a few added primitives for git) with another that's also called git annex (basically a replacement for content tracking in git - and isn't that basically a replacement for git?).
-
-I realize every user's going to have slightly different preferences, but I truly think this is the rare case where simply saying \"if you don't like it, set these flags in your repos' configs\" is not nearly good enough.
-I realize it would be a pain to roll this change back, but the benefits still far outweigh the costs. It's going to be a much bigger pain point for all users who are suddenly confused and have put their history in a broken state, for all the tutorials that are now giving users inaccurate information, etc.
-
-## Worse experience for new/inexperienced users
-
-Anecdotally, I've turned 5-10 people on to the beauty of git annex, and in every case the reason I told them about it was they mentioned to me they needed some way to store a large data file in their existing code repository. 
-
-Now when I tell people about git annex, I have to also tell them to be super careful to set up a set of configs in orer for it not to fundamentally redefine the meaning of their repo?
-
-The common new-user experience for me has been:
-
->  Friend (from across the room): \"Dang, this file's too big for git\"
-
->  Me: \"Have you tried git annex?\"
-
->  [...talking about the benefits, installation, etc...]
-
->  Friend: \"Ok now how do I use it?\"
-
->  Me (still across the room): \"Just 'git annex init' in the repo and then 'git annex add' the file\"
-
-It seems almost comical that I'd memorize a line so I could instead say:
-
->  Me: \"Just 'git annex init' in the repo and then 'git annex add' the file. But first be SUPER careful to type 'git config annex.largefiles 'largerthan=100kb and not (include=*.c or include=*.h)' and don't forget to keep that list of file extensions up to date\"
-
-\"git annex init\" should be set-it-and-forget-it. I shouldn't have to worry about what parts of my git repo it's messing with because I'm not being vigilant enough.
-
-## Should have been discussed and then announced far more widely
-
-I go to the git annex homepage every couple of weeks, which I imagine is on the high end for a user of a command line tool. Even I was caught completely by surprise with this change, and only saw it when I \"apt-upgrade\"d.
-
-
-## (Subjective:) Worse even if it didn't break (most?) users' expectations
-
-IMO, even if this were a new tool with no existing users or workflows or repos, this would not be the best default and instead should be behind a flag. I know I'd have been less enthusiastic to start using it if it were nudging me to basically use it as a replacement for Dropbox, instead of an unobtrusive set of additional tools for git.
-
-I'd also be less enthusiastic to know that if I weren't vigilant I'd get totally wrong behavior (e.g. I say 'git config annex.largefiles 'largerthan=100kb and not (include=*.c or include=*.h)' but then I \"git add\" a .hsc file and it \"git-annex-add\"s it \"behind my back\")
-
-## In summary:
-
-Issues as I see it are (and there may be more):
-
-  * It breaks users' workflows. Potentially a huge number of them. This alone should be a big reason to be careful when making a change like this.
-    I - one single user - have already spent hours assessing how this will affect me and my repos. It requires me to be very careful and I'm far from sure I won't slip up somewhere. Hopefully if/when I do, I'll notice the mistake.
-    I had other things planned for my Saturday, but some of them involved using \"git annex\" and so now I have to halt everything to make sure I'm not screwing anything up now that I \"apt upgrade\"d and got a new version of git-annex this morning.
-  * Uncomfortable new-user experience
-  * (Subjective:) not a good default even if didn't break expectations
-  * Should have been announced and discussed MUCH more widely and extensively
-
-
-## A response to a few issues already raised:
-
-> \"Suppose you have an unlocked file in your repo, and you rename it (not using git move), and then git add it. Oops, now you've added to git a large file that you wanted to be annexed. \"
-
-Why not simply provide a configurable warning about attempting to \"git add\" a file above a certain size? A \"did you mean 'git annex add'?\" type warning would be helpful for everyone. It'd catch all mistakes, not just ones caused by mv.
-
-> \"But mv foo bar; git add bar is normally identical to git mv foo bar. Why should using git-annex break that identity?\"
-
-This to me feels like killing a mosquito with a sledgehammer. This change breaks myriad other identities, including a very simple one:
-  - \"git add\"ing a new file should behave the same whether or not we've at some point typed \"git annex init\"
-
-The \"mv ; add\" identity has never been an issue for me in years of using git annex. By contrast, this change has already eaten up half of my Saturday. (Admittedly some of it writing this up. And again I should mention: I still hugely appreciate all the work on git-annex!)
-
-## What to do about it?
-
-I'm 100% behind Dwk's 4-point plan.
-My one clarification is potentially to take \"only if largefiles is set\" to mean \"only if largefiles is set to a value other than 'nothing'.\" Not sure about this one.
-
-
-
-"""]]
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_12_ea51470a483da0ca38156d68df30184b._comment b/doc/forum/lets_discuss_git_add_behavior/comment_12_ea51470a483da0ca38156d68df30184b._comment
deleted file mode 100644
index a2c9aec76..000000000
--- a/doc/forum/lets_discuss_git_add_behavior/comment_12_ea51470a483da0ca38156d68df30184b._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="Ilya_Shlyakhter"
- avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
- subject="experience with v7 semantics"
- date="2019-10-12T21:39:03Z"
- content="""
-To add to the anecdotal reports of user experience, I find myself periodically running `git annex lock` just to make sure nothing got inadvertently unlocked, or added as unlocked.  The main benefit of using `git-annex` to version data analysis results, besides avoiding git's choking on large files or breaking github size limits, is the certainty that the result files are exactly as originally output, and haven't been accidentally changed (e.g. by re-running the analysis with different parameters but same output file name).  With locked files, I have that guarantee -- once added and committed, the files won't change unless explicitly unlocked.  With unlocked files, there's a chance of changing the file and then not noticing the change and committing it.  The git log will of course reflect the change, but I might miss it, unless I inspect the log.  So it's important to have a foolproof way to prevent files from being added as unlocked, and that's hard to do with the current `git-annex` version.  I can set `annex.largefiles=nothing` at the repo root, but then `git annex add` won't annex anything, either.  One solution is [[todo/separate_annex.largefiles.git-add_and_annex.largefiles.git-annex-add_settings]]; there may be others.
-"""]]
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_13_81373a9181bcf7c80f06936e62742678._comment b/doc/forum/lets_discuss_git_add_behavior/comment_13_81373a9181bcf7c80f06936e62742678._comment
deleted file mode 100644
index 73706daa3..000000000
--- a/doc/forum/lets_discuss_git_add_behavior/comment_13_81373a9181bcf7c80f06936e62742678._comment
+++ /dev/null
@@ -1,9 +0,0 @@
-[[!comment format=mdwn
- username="Lukey"
- avatar="http://cdn.libravatar.org/avatar/c7c08e2efd29c692cc017c4a4ca3406b"
- subject="v5 mode"
- date="2019-10-12T21:48:56Z"
- content="""
-Maybe something like \"git annex v5mode true\" is needed so we get v5 semantics in v7 mode.

(Diff truncated)
response
diff --git a/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_1_981279bae881a07185707c29e6c58b28._comment b/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_1_981279bae881a07185707c29e6c58b28._comment
new file mode 100644
index 000000000..3fbfccae9
--- /dev/null
+++ b/doc/forum/Performance_of_V6__44___V7__44___V8_repos/comment_1_981279bae881a07185707c29e6c58b28._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-21T18:50:00Z"
+ content="""
+There is no change at all for performance when annexed files are symlinks.
+
+If the annexed file is unlocked, it will use smudge/clean filters.
+
+If you have non-annexed files in the git repo, git will also run those
+through the smudge/clean filters.
+
+git calls the clean filter when it sees a file has been modified.
+Things like git status and git add. It caches the result until the file is
+modified again. The smudge filter is only called when git is checking out
+a file (git checkout or a change from a git pull etc).
+"""]]

fix embedcreds=yes reversion
Fix bug that made enableremote of S3 and webdav remotes, that have
embedcreds=yes, fail to set up the embedded creds, so accessing the remotes
failed.
(Regression introduced in version 7.20200202.7 in when reworking all the
remote configs to be parsed.)
Root problem is that parseEncryptionConfig excludes all other config keys
except encryption ones, so it is then unable to find the
credPairRemoteField. And since that field is not required to be
present, it proceeds as if it's not, rather than failing in any visible
way.
This causes it to not find any creds, and so it does not cache
them. When when the S3 remote tries to make a S3 connection, it finds no
creds, so assumes it's being used in no-creds mode, and tries to find a
public url. With no public url available, it fails, but the failure doesn't
say a lack of creds is the problem.
Fix is to provide setRemoteCredPair with a ParsedRemoteConfig, so the full
set of configs of the remote can be parsed. A bit annoying to need to
parse the remote config before the full config (as returned by
setRemoteCredPair) is available, but this avoids the problem.
I assume webdav also had the problem by inspection, but didn't try to
reproduce it with it.
Also, getRemoteCredPair used getRemoteConfigValue to get a ProposedAccepted
String, but that does not seem right. Now that it runs that code, it
crashed saying it had just a String.
Remotes that have already been enableremoted, and so lack the cached creds
file will work after this fix, because getRemoteCredPair will extract
the creds from the remote config, writing the missing file.
This commit was sponsored by Ilya Shlyakhter on Patreon.
diff --git a/CHANGELOG b/CHANGELOG
index 82c8eea90..1072e9390 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,6 +28,9 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
     directory that's a symbolic link to elsewhere.
   * When accessing a remote fails, always display a reason why.
   * whereis: Added --format option.
+  * Fix bug that made enableremote of S3 and webdav remotes, that
+    have embedcreds=yes, fail to set up the embedded creds, so accessing
+    the remotes failed. (Regression introduced in version 7.20200202.7)
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Creds.hs b/Creds.hs
index 766cf709b..2852906ec 100644
--- a/Creds.hs
+++ b/Creds.hs
@@ -31,7 +31,7 @@ import Utility.FileMode
 import Crypto
 import Types.Remote (RemoteConfig, RemoteConfigField)
 import Types.ProposedAccepted
-import Remote.Helper.Encryptable (remoteCipher, remoteCipher', embedCreds, EncryptionIsSetup, extractCipher, parseEncryptionConfig)
+import Remote.Helper.Encryptable (remoteCipher, remoteCipher', embedCreds, EncryptionIsSetup, extractCipher)
 import Utility.Env (getEnv)
 
 import qualified Data.ByteString.Lazy.Char8 as L
@@ -56,10 +56,8 @@ data CredPairStorage = CredPairStorage
  - if that's going to be done, so that the creds can be encrypted using the
  - cipher. The EncryptionIsSetup is witness to that being the case.
  -}
-setRemoteCredPair :: EncryptionIsSetup -> RemoteConfig -> RemoteGitConfig -> CredPairStorage -> Maybe CredPair -> Annex RemoteConfig
-setRemoteCredPair = setRemoteCredPair' id go
-  where
-	go c = either (const (ParsedRemoteConfig mempty c)) id (parseEncryptionConfig c)
+setRemoteCredPair :: EncryptionIsSetup -> ParsedRemoteConfig -> RemoteGitConfig -> CredPairStorage -> Maybe CredPair -> Annex RemoteConfig
+setRemoteCredPair encsetup pc = setRemoteCredPair' id (const pc) encsetup (unparsedRemoteConfig pc)
 
 setRemoteCredPair'
 	:: (ProposedAccepted String -> a)
@@ -106,7 +104,7 @@ getRemoteCredPair c gc storage = maybe fromcache (return . Just) =<< fromenv
 	fromconfig = do
 		let key = credPairRemoteField storage
 		mcipher <- remoteCipher' c gc
-		case (fromProposedAccepted <$> getRemoteConfigValue key c, mcipher) of
+		case (getRemoteConfigValue key c, mcipher) of
 			(Nothing, _) -> return Nothing
 			(Just enccreds, Just (cipher, storablecipher)) ->
 				fromenccreds enccreds cipher storablecipher
diff --git a/Remote/Glacier.hs b/Remote/Glacier.hs
index 662363ed1..dfba203b6 100644
--- a/Remote/Glacier.hs
+++ b/Remote/Glacier.hs
@@ -118,16 +118,17 @@ glacierSetup ss mu mcreds c gc = do
 	glacierSetup' ss u mcreds c gc
 glacierSetup' :: SetupStage -> UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> Annex (RemoteConfig, UUID)
 glacierSetup' ss u mcreds c gc = do
-	(c', encsetup) <- encryptionSetup c gc
-	c'' <- setRemoteCredPair encsetup c' gc (AWS.creds u) mcreds
-	let fullconfig = c'' `M.union` defaults
-	pc <- either giveup return . parseRemoteConfig fullconfig
-		=<< configParser remote fullconfig
+	(c', encsetup) <- encryptionSetup (c `M.union` defaults) gc
+	pc <- either giveup return . parseRemoteConfig c'
+		=<< configParser remote c'
+	c'' <- setRemoteCredPair encsetup pc gc (AWS.creds u) mcreds
+	pc' <- either giveup return . parseRemoteConfig c''
+		=<< configParser remote c''
 	case ss of
-		Init -> genVault pc gc u
+		Init -> genVault pc' gc u
 		_ -> return ()
-	gitConfigSpecialRemote u fullconfig [("glacier", "true")]
-	return (fullconfig, u)
+	gitConfigSpecialRemote u c'' [("glacier", "true")]
+	return (c'', u)
   where
 	remotename = fromJust (lookupName c)
 	defvault = remotename ++ "-" ++ fromUUID u
diff --git a/Remote/Helper/Chunked.hs b/Remote/Helper/Chunked.hs
index e22845af0..ab337a5a6 100644
--- a/Remote/Helper/Chunked.hs
+++ b/Remote/Helper/Chunked.hs
@@ -247,13 +247,14 @@ retrieveChunks retriever u chunkconfig encryptor basek dest basep sink
 		let ls' = maybe ls (setupResume ls) currsize
 		if any null ls'
 			then noop -- dest is already complete
-			else firstavail currsize ls'
+			else firstavail Nothing currsize ls'
 
-	firstavail _ [] = giveup "chunk retrieval failed"
-	firstavail currsize ([]:ls) = firstavail currsize ls
-	firstavail currsize ((k:ks):ls)
+	firstavail Nothing _ [] = giveup "chunk retrieval failed"
+	firstavail (Just e) _ [] = throwM e
+	firstavail pe currsize ([]:ls) = firstavail pe currsize ls
+	firstavail _ currsize ((k:ks):ls)
 		| k == basek = getunchunked
-			`catchNonAsync` (const $ firstavail currsize ls)
+			`catchNonAsync` (\e -> firstavail (Just e) currsize ls)
 		| otherwise = do
 			let offset = resumeOffset currsize k
 			let p = maybe basep
@@ -269,7 +270,7 @@ retrieveChunks retriever u chunkconfig encryptor basek dest basep sink
 			case v of
 				Left e
 					| null ls -> throwM e
-					| otherwise -> firstavail currsize ls
+					| otherwise -> firstavail (Just e) currsize ls
 				Right r -> return r
 
 	getrest _ _ _ _ [] = noop
diff --git a/Remote/S3.hs b/Remote/S3.hs
index 3e414843a..9bcd79333 100644
--- a/Remote/S3.hs
+++ b/Remote/S3.hs
@@ -243,7 +243,7 @@ s3Setup ss mu mcreds c gc = do
 	s3Setup' ss u mcreds c gc
 
 s3Setup' :: SetupStage -> UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> Annex (RemoteConfig, UUID)
-s3Setup' ss u mcreds c gc
+s3Setup'  ss u mcreds c gc
 	| maybe False (isIAHost . fromProposedAccepted) (M.lookup hostField c) = archiveorg
 	| otherwise = defaulthost
   where
@@ -263,21 +263,24 @@ s3Setup' ss u mcreds c gc
 		return (fullconfig, u)
 
 	defaulthost = do
-		(c', encsetup) <- encryptionSetup c gc
-		c'' <- setRemoteCredPair encsetup c' gc (AWS.creds u) mcreds
-		let fullconfig = c'' `M.union` defaults
-		pc <- either giveup return . parseRemoteConfig fullconfig
-			=<< configParser remote fullconfig
-		info <- extractS3Info pc
-		checkexportimportsafe pc info
+		(c', encsetup) <- encryptionSetup (c `M.union` defaults) gc
+		pc <- either giveup return . parseRemoteConfig c'
+			=<< configParser remote c'
+		c'' <- setRemoteCredPair encsetup pc gc (AWS.creds u) mcreds
+		pc' <- either giveup return . parseRemoteConfig c''
+			=<< configParser remote c''
+		info <- extractS3Info pc'
+		checkexportimportsafe pc' info
 		case ss of
-			Init -> genBucket pc gc u
+			Init -> genBucket pc' gc u
 			_ -> return ()
-		use fullconfig pc info
+		use c'' pc' info
 
 	archiveorg = do
 		showNote "Internet Archive mode"
-		c' <- setRemoteCredPair noEncryptionUsed c gc (AWS.creds u) mcreds
+		pc <- either giveup return . parseRemoteConfig c
+			=<< configParser remote c
+		c' <- setRemoteCredPair noEncryptionUsed pc gc (AWS.creds u) mcreds
 		-- Ensure user enters a valid bucket name, since
 		-- this determines the name of the archive.org item.
 		let validbucket = replace " " "-" $ map toLower $
@@ -292,14 +295,14 @@ s3Setup' ss u mcreds c gc
 			M.union c' $
 			-- special constraints on key names
 			M.insert mungekeysField (Proposed "ia") defaults
-		pc <- either giveup return . parseRemoteConfig archiveconfig
+		pc' <- either giveup return . parseRemoteConfig archiveconfig
 			=<< configParser remote archiveconfig
-		info <- extractS3Info pc
-		checkexportimportsafe pc info
-		hdl <- mkS3HandleVar pc gc u
+		info <- extractS3Info pc'
+		checkexportimportsafe pc' info
+		hdl <- mkS3HandleVar pc' gc u
 		withS3HandleOrFail u hdl $
-			writeUUIDFile pc u info
-		use archiveconfig pc info
+			writeUUIDFile pc' u info
+		use archiveconfig pc' info
 	
 	checkexportimportsafe c' info =
 		unlessM (Annex.getState Annex.force) $
diff --git a/Remote/WebDAV.hs b/Remote/WebDAV.hs
index 1d6cafc9f..018987d40 100644
--- a/Remote/WebDAV.hs
+++ b/Remote/WebDAV.hs
@@ -134,7 +134,7 @@ webdavSetup _ mu mcreds c gc = do
 	creds <- maybe (getCreds pc gc u) (return . Just) mcreds
 	testDav url creds
 	gitConfigSpecialRemote u c' [("webdav", "true")]
-	c'' <- setRemoteCredPair encsetup c' gc (davCreds u) creds
+	c'' <- setRemoteCredPair encsetup pc gc (davCreds u) creds
 	return (c'', u)
 
 store :: DavHandleVar -> ChunkConfig -> Storer
diff --git a/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn
index 315f6bfdd..9787eb1a7 100644
--- a/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn
+++ b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn
@@ -55,3 +55,4 @@ Linux, Ubuntu 20.04
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)

(Diff truncated)
Added a comment
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_38_000a5acd8231125e5be127bfd72935a3._comment b/doc/forum/lets_discuss_git_add_behavior/comment_38_000a5acd8231125e5be127bfd72935a3._comment
new file mode 100644
index 000000000..b7239145f
--- /dev/null
+++ b/doc/forum/lets_discuss_git_add_behavior/comment_38_000a5acd8231125e5be127bfd72935a3._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="codelix"
+ avatar="http://cdn.libravatar.org/avatar/667ff4d0387694f28236639bab0faf2c"
+ subject="comment 38"
+ date="2020-05-21T18:00:57Z"
+ content="""
+Actually, even better it could be something like this
+
+~~~
+cat .gitannexinclude
++ *.ogg
++ *.mp3
++ > 100MB
+
+- .*
+- < 3MB
+~~~
+
+Any statement lower down overrides a statement higher up. Any file that does not match any of these patterns is automatically added to git. This will let us deprecate options like `largefiles` which are a source of lot of confusion for at least me.
+"""]]

Added a comment: SO frustrating
diff --git a/doc/forum/lets_discuss_git_add_behavior/comment_37_b8b326f69bfb5b7109cab8f60e64ae60._comment b/doc/forum/lets_discuss_git_add_behavior/comment_37_b8b326f69bfb5b7109cab8f60e64ae60._comment
new file mode 100644
index 000000000..fba8b0798
--- /dev/null
+++ b/doc/forum/lets_discuss_git_add_behavior/comment_37_b8b326f69bfb5b7109cab8f60e64ae60._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="codelix"
+ avatar="http://cdn.libravatar.org/avatar/667ff4d0387694f28236639bab0faf2c"
+ subject="SO frustrating"
+ date="2020-05-21T17:55:09Z"
+ content="""
+I am a big big fan of Joey and a big big fan of git annex, been using this for 7+ years. I absolutely love the reasoning that Joey does and how we identifies the best way to solve any problem.
+
+But this is the first change that does what I consider to be a major mistake. It's essentially had me rethinking whether I can trust git annex anymore, and am tempted to continue using older versions which come with their own problems. It essentially all comes down to \"sane defaults\". Joey's reasonings are absolutely bang on, but optimizing for a very specific use case and silently doing things behind the scenes does not make sense.
+
+For instance, git lfs does not add all files to lfs silently, but this essentially makes git annex do that in a sense.
+
+My understanding is that this has been changed to some extent in recent versions, but I'm not 100% sure what the state is. In any case, I propose something like this
+
+* Sane default -> git add ALWAYS adds files to git, git annex add ALWAYS add files to git annex, no exceptions
+* Permit configuring which files get added to annex by git add, or to git by git annex add.
+  Honestly, it's becoming super confusing how all the different options like largefiles interact with each other. For this purpose, I suggest having a new namespace/version of configs that cleans this up, to maybe something like.
+
+~~~
+cat .gitaddtoannex
+*.ogg
+*.mp3
+> 100MB
+
+cat .gitannexaddtogit
+.*
+< 3MB
+~~~
+
+I feel this will simplify the part and making it super clear what will happen. Having the same behavior for `git mv` and `mv` can be handled as suggested already. Please let me know your thoughts on this, Joey.
+
+Greatly appreciate all the work you are doing and hope we can continue to keep git annex the rock solid option it is. I think simplifying some of these configs will also help make it more accessible to less techie folks as well.
+"""]]

comment
diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_2_b279bd82612c0bee486c877e700ccbe4._comment b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_2_b279bd82612c0bee486c877e700ccbe4._comment
new file mode 100644
index 000000000..5e1db4285
--- /dev/null
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_2_b279bd82612c0bee486c877e700ccbe4._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2020-05-21T16:54:48Z"
+ content="""
+I don't think there's any reason why git should need to allocate memory for
+the whole file. All it's doing is reading the file and sending it over a
+pipe, and git-annex actually hangs up the pipe before reading anything.
+So git could read a few bytes, try to send them, and give up.
+
+The last time I looked at it, in [[!commit a96972015dd76271b46432151e15d5d38d7151ff]]
+having git-annex close the pipe immediately did avoid git overallocating
+memory. I don't know what else git-annex could do to avoid any bad behavior
+from git.
+
+If your git is older than 2.5, it would certainly explain it, since the
+above workaround needed git 2.5.
+"""]]
diff --git a/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients/comment_1_48953f4f0eacdba05b200f972204270d._comment b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients/comment_1_48953f4f0eacdba05b200f972204270d._comment
new file mode 100644
index 000000000..821d96395
--- /dev/null
+++ b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients/comment_1_48953f4f0eacdba05b200f972204270d._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-21T16:34:34Z"
+ content="""
+I tried this and the result is that git-annex get from S3 fails. While I do
+think it should be writing the creds cache file, the failure to get is the
+actual bug symptom.
+"""]]

Added a comment
diff --git a/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_3_1b84261a9e6389bcad1766b82add4930._comment b/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_3_1b84261a9e6389bcad1766b82add4930._comment
new file mode 100644
index 000000000..04221cbe2
--- /dev/null
+++ b/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_3_1b84261a9e6389bcad1766b82add4930._comment
@@ -0,0 +1,52 @@
+[[!comment format=mdwn
+ username="kyle"
+ avatar="http://cdn.libravatar.org/avatar/7d6e85cde1422ad60607c87fa87c63f3"
+ subject="comment 3"
+ date="2020-05-21T17:06:12Z"
+ content="""
+> If I revert to a previous commit, the metadata changes are not
+> reverted to their previous state.
+
+Metadata is attached to keys, not files.  (See `man
+git-annex-metadata`.)  If the state you revert to has the same key, it
+will have the same associated metadata.
+
+> Is there a way to revert metadata?
+
+AFAIU not in a way that is tied to the HEAD commit.  You can run `git
+annex metadata --remove-all FILE`, but that will remove the metadata
+on the underlying key.
+
+> If I understood that correctly, the metadata are stored in a single
+> git-annex branch: so there is no way to have two regular branches with
+> different metadata for the same file, right?
+
+Correct.
+
+> Does any call to git-annex metadata creates a new commit in the
+> git-annex branch?
+
+I believe so, provided the caller hasn't overridden
+`annex.alwayscommit` to \"false\".
+
+> The commit message of the git-annex branch are not super
+> informative: they all say \"update\".
+
+In my view generic messages like \"update\" make a lot of sense in the
+context of the behind-the-scenes git-annex branch.  If you're
+inspecting it just because you're curious about what's happening
+underneath, you might find the output of `git log --stat git-annex`
+helpful.
+
+That being said, there is an `annex.commitmessage` config option if
+you want to override the message.
+
+https://git-annex.branchable.com/todo/be_able_to_specify_custom_commit_message_for_git-annex_branch_commit/
+
+> A related question: is there a way to get the git-annex branch commit
+> that matches a regular/master branch commit?
+
+I don't think there is any such mapping by design.
+
+
+"""]]

diff --git a/doc/forum/Performance_of_V6__44___V7__44___V8_repos.mdwn b/doc/forum/Performance_of_V6__44___V7__44___V8_repos.mdwn
new file mode 100644
index 000000000..0566f53f4
--- /dev/null
+++ b/doc/forum/Performance_of_V6__44___V7__44___V8_repos.mdwn
@@ -0,0 +1,8 @@
+Hey folks (and Joey), I am trying to understand the performance impact of changes in v6 -> v7 -> v8 mode. Apologies since I haven't kept up with the changes (was using older version for quite a bit) and some of these might already be well documented/known.
+
+Essentially, back in v6 and earlier, I was pretty happy with the design idea the git annex doesn't use smudge/clean filters since their performance is far from ideal. However, I see that in newer versions of repos, this has become more of a thing. I have read a few docs (https://git-annex.branchable.com/todo/git_smudge_clean_interface_suboptiomal/, https://git-annex.branchable.com/todo/only_pass_unlocked_files_through_the_clean__47__smudge_filter/) but there's still a few thing I don't understand.
+
+1) Are smudge/clean filter used all the time now? Does this mean that we are taking a performance hit compared to older git annex versions?
+2) Can someone explain when smudge/clean filters get used? Is it only in repos that use unlock/adjust? I don't use either of them, and would love to know if these are being used unnecessarily.
+
+Thanks in advance!

followup and close
diff --git a/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn b/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn
index 6212eb2cb..f77f68068 100644
--- a/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn
+++ b/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn
@@ -45,3 +45,4 @@ commit 6f7b889c3487fb6dacbfd7a3a6fa8c55ea3ed274
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
 I keep coming back to it, it's given me a steady stream of frustration and satisfaction for over 5 years.
 
+> [[notabug|done]] --[[Joey]]
diff --git a/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_3_ff2e22dae90a858c46cb39c4af2a6842._comment b/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_3_ff2e22dae90a858c46cb39c4af2a6842._comment
new file mode 100644
index 000000000..429e00ff9
--- /dev/null
+++ b/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_3_ff2e22dae90a858c46cb39c4af2a6842._comment
@@ -0,0 +1,21 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2020-05-21T16:17:55Z"
+ content="""
+As whereis shows, the content of your file is located only on the repository
+chymera@localhost.localdomain:~/data
+
+When you ran git-annex get in chymera@silenthost:~/data, it did not have any
+remote that connected it to that repository, so it had no way to get the content. Its only remote,
+/run/media/chymera/data0/data, did not contain the content.
+
+The data is being correctly tracked. I do not see any bug here.
+
+You need to track down the chymera@localhost.localdomain:~/data repository, add
+a remote pointing to it, and everything will work. Unfortunately, it seems
+whatever computer it's located on, git-annex was not able to get a better
+hostname for than "localhost", which is kind of unusual. git-annex simply runs
+"uname -n" to get the hostname, so whichever of your computers that outputs
+"localhost" on is probably the one.
+"""]]

improve docs around uri claiming
diff --git a/Types/Remote.hs b/Types/Remote.hs
index 1b95bc741..a5efff16b 100644
--- a/Types/Remote.hs
+++ b/Types/Remote.hs
@@ -149,7 +149,10 @@ data RemoteA a = Remote
 	, mkUnavailable :: a (Maybe (RemoteA a))
 	-- Information about the remote, for git annex info to display.
 	, getInfo :: a [(String, String)]
-	-- Some remotes can download from an url (or uri).
+	-- Some remotes can download from an url (or uri). This asks the
+	-- remote if it can handle a particular url. The actual download
+	-- will be done using retrieveKeyFile, and the remote can look up
+	-- up the url to download for a key using Logs.Web.getUrls.
 	, claimUrl :: Maybe (URLString -> a Bool)
 	-- Checks that the url is accessible, and gets information about
 	-- its contents, without downloading the full content.
diff --git a/doc/design/external_special_remote_protocol.mdwn b/doc/design/external_special_remote_protocol.mdwn
index 2885a2469..35cbc5ec8 100644
--- a/doc/design/external_special_remote_protocol.mdwn
+++ b/doc/design/external_special_remote_protocol.mdwn
@@ -365,9 +365,8 @@ handling a request.
   URL.  
   (git-annex does not send a reply to this message.)
 * `SETURIPRESENT Key Uri`  
-  Records an URI where the Key can be downloaded from.  
-  For example, "ipfs:ADDRESS" is used for the ipfs special remote;
-  its CLAIMURL handler checks for such URIS and claims them.  
+  Records an URI where the Key can be downloaded from. Use with uris
+  that cannot be downloaded with http.
   (git-annex does not send a reply to this message.)
 * `SETURIMISSING Key Uri`  
   Records that the key can no longer be downloaded from the specified
@@ -420,7 +419,38 @@ quite a long time, especially when the git-annex assistant is using it.
 The assistant will detect when the system connects to a network, and will
 start a new process the next time it needs to use a remote.
 
-## readonly mode
+## claiming custom uri schemes for use with git-annex addurl
+
+If a special remote has its own uri scheme, or some other way to identify a
+particular url as being content that is stored in the special remote,
+and can be downloaded by it, it can implement CLAIMURL and CHECKURL.
+This lets git-annex addurl be used with such urls.
+
+For example, the ipfs special remote implements CLAIMURL and CHECKURL
+for "ipfs:ADDRESS" uris. And the bittorrent special remote implements them
+for http urls ending in ".torrent".
+
+When a special remote has claimed an url, commands like git-annex addurl
+will use TRANSFER RETRIEVE to request it download the content of a key.
+To find out what url to download, the special remote can use GETURLS
+to find out what urls are recorded for the key.
+
+For example, the ipfs special remote sends "GETURLS $KEY ipfs:",
+in order to get only the "ipfs:" uris.
+
+The special remote can also use SETURIPRESENT or SETURLPRESENT,
+eg after transferring content to the remote it might know the uri or url
+that can be used to download it. And SETURIMISSING or SETURLMISSING
+can be used after removing content from the remote. This information can
+then be looked up using GETURLS. But it's not necessary to do this in order
+to simply claim an url, because git-annex addurl takes care of it.
+
+For example, the ipfs special remote sends "SETURIPRESENT $KEY ipfs:ADDRESS"
+after storing each key in ipfs. It can later look up that uri when
+downloading the key, and the ipfs uri is also displayed by git-annex
+whereis.
+
+## readonly mode for http downloads
 
 Some storage services allow downloading the content of a file using a
 regular http connection, with no authentication. An external special remote

Added a comment: reverting metadata
diff --git a/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_2_8f02d0c400d22866e38cc521dd55b2c2._comment b/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_2_8f02d0c400d22866e38cc521dd55b2c2._comment
new file mode 100644
index 000000000..a8081ccf5
--- /dev/null
+++ b/doc/forum/How_do_I_revert_back_to_specific_commit_with_git_annex/comment_2_8f02d0c400d22866e38cc521dd55b2c2._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="basile.pinsard@f1a7fae9f3bd9d5282fca11f62ad53b45a8eb317"
+ nickname="basile.pinsard"
+ avatar="http://cdn.libravatar.org/avatar/87e1f73acf277ad0337b90fc0253c62e"
+ subject="reverting metadata"
+ date="2020-05-21T13:39:37Z"
+ content="""
+If I revert to a previous commit, the metadata changes are not reverted to their previous state.
+Is there a way to revert metadata?
+If I understood that correctly, the metadata are stored in a single git-annex branch: so there is no way to have two regular branches with different metadata for the same file, right?
+Does any call to git-annex metadata creates a new commit in the git-annex branch?
+The commit message of the git-annex branch are not super informative: they all say \"update\".
+
+A related question: is there a way to get the git-annex branch commit that matches a regular/master branch commit?
+
+Thanks.
+"""]]

Added a comment
diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_2_1fcefda1f6d405a211b6eadf42416ee5._comment b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_2_1fcefda1f6d405a211b6eadf42416ee5._comment
new file mode 100644
index 000000000..57edbd166
--- /dev/null
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_2_1fcefda1f6d405a211b6eadf42416ee5._comment
@@ -0,0 +1,28 @@
+[[!comment format=mdwn
+ username="braun.markus89@51b521a42cc994db864df308627bd6454f9c309d"
+ nickname="braun.markus89"
+ avatar="http://cdn.libravatar.org/avatar/c11d06a0d9db6a9472b05ee01c342ca4"
+ subject="comment 2"
+ date="2020-05-20T13:54:23Z"
+ content="""
+Thanks for your answer. 
+
+Short follow up question.
+When I do exactly the same for a 2G file, something similar happens:
+
+    $ git annex sync --debug
+    [2020-05-20 15:48:19.441795963] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"show-ref\",\"git-annex\"]
+    [2020-05-20 15:48:19.459542967] process done ExitSuccess
+    [2020-05-20 15:48:19.460055539] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+    [2020-05-20 15:48:19.47249456] process done ExitSuccess
+    [2020-05-20 15:48:19.473466546] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"log\",\"refs/heads/git-annex..9655aad25802451eb83141096fb9275aa36fe810\",\"--pretty=%H\",\"-n1\"]
+    [2020-05-20 15:48:19.487917815] process done ExitSuccess
+    [2020-05-20 15:48:19.489243941] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"cat-file\",\"--batch\"]
+    [2020-05-20 15:48:19.490737137] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"cat-file\",\"--batch-check=%(objectname) %(objecttype) %(objectsize)\"]
+    commit 
+    [2020-05-20 15:48:19.506415618] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"commit\",\"-a\",\"-m\",\"git-annex in admin@Paintower:~/git-annex/test\"]
+    fatal: mmap failed: Cannot allocate memory
+
+So why does the \"git commit\" allocate so much memory? It seems like it tries to handle the file content itself? Or is it a malloc failure caused by git annex smudge?
+
+"""]]

whereis: Added --format option.
One way this can be used is to remove all urls for some website that went
away:
git-annex whereis --format '${file} ${url}\0' | \
grep -z whatever.com | git-annex rmurl --batch -z
Combining ${url} and ${uuid} is a bit of a combinatorial explosion.
It didn't seem worth only outputting a uuid alongside an url belonging
to it, so each uuid is output beside each url.
diff --git a/CHANGELOG b/CHANGELOG
index a2b3eea9e..82c8eea90 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -27,6 +27,7 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
   * Display a warning message when asked to operate on a file inside a
     directory that's a symbolic link to elsewhere.
   * When accessing a remote fails, always display a reason why.
+  * whereis: Added --format option.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Command/Whereis.hs b/Command/Whereis.hs
index 8e0ecb9e8..0b850ef8e 100644
--- a/Command/Whereis.hs
+++ b/Command/Whereis.hs
@@ -1,10 +1,12 @@
 {- git-annex command
  -
- - Copyright 2010-2016 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
 
+{-# LANGUAGE TupleSections #-}
+
 module Command.Whereis where
 
 import Command
@@ -13,6 +15,9 @@ import Logs.Trust
 import Logs.Web
 import Remote.Web (getWebUrls)
 import Annex.UUID
+import qualified Utility.Format
+import qualified Command.Find
+import Types.ActionItem
 
 import qualified Data.Map as M
 import qualified Data.Vector as V
@@ -27,6 +32,7 @@ data WhereisOptions = WhereisOptions
 	{ whereisFiles :: CmdParams
 	, keyOptions :: Maybe KeyOptions
 	, batchOption :: BatchMode
+	, formatOption :: Maybe Utility.Format.Format
 	}
 
 optParser :: CmdParamsDesc -> Parser WhereisOptions
@@ -34,40 +40,74 @@ optParser desc = WhereisOptions
 	<$> cmdParams desc
 	<*> optional parseKeyOptions
 	<*> parseBatchOption
+	<*> optional parseFormatOption
+
+parseFormatOption :: Parser Utility.Format.Format
+parseFormatOption = option (Utility.Format.gen <$> str)
+	( long "format" <> metavar paramFormat
+	<> help "control format of output"
+	)
 
 seek :: WhereisOptions -> CommandSeek
 seek o = do
 	m <- remoteMap id
-	let go = whenAnnexed $ start m
+	let go = whenAnnexed $ start o m
 	case batchOption o of
 		Batch fmt -> batchFilesMatching fmt (go . toRawFilePath)
 		NoBatch -> 
 			withKeyOptions (keyOptions o) False
-				(commandAction . startKeys m)
+				(commandAction . startKeys o m)
 				(withFilesInGit (commandAction . go))
 				=<< workTreeItems (whereisFiles o)
 
-start :: M.Map UUID Remote -> RawFilePath -> Key -> CommandStart
-start remotemap file key = startKeys remotemap (key, mkActionItem (key, afile))
+start :: WhereisOptions -> M.Map UUID Remote -> RawFilePath -> Key -> CommandStart
+start o remotemap file key = 
+	startKeys o remotemap (key, mkActionItem (key, afile))
   where
 	afile = AssociatedFile (Just file)
 
-startKeys :: M.Map UUID Remote -> (Key, ActionItem) -> CommandStart
-startKeys remotemap (key, ai) = starting "whereis" ai $ perform remotemap key
+startKeys :: WhereisOptions -> M.Map UUID Remote -> (Key, ActionItem) -> CommandStart
+startKeys o remotemap (key, ai)
+	| isJust (formatOption o) = startingCustomOutput ai go
+	| otherwise = starting "whereis" ai go
+  where
+	go = perform o remotemap key ai
 
-perform :: M.Map UUID Remote -> Key -> CommandPerform
-perform remotemap key = do
+perform :: WhereisOptions -> M.Map UUID Remote -> Key -> ActionItem -> CommandPerform
+perform o remotemap key ai = do
 	locations <- keyLocations key
 	urls <- getUUIDUrls key locations remotemap
 	(untrustedlocations, safelocations) <- trustPartition UnTrusted locations
-	let num = length safelocations
-	showNote $ show num ++ " " ++ copiesplural num
-	pp <- ppwhereis "whereis" safelocations urls
-	unless (null safelocations) $ showLongNote pp
-	pp' <- ppwhereis "untrusted" untrustedlocations urls
-	unless (null untrustedlocations) $ showLongNote $ untrustedheader ++ pp'
-
-	mapM_ (showRemoteUrls remotemap) urls
+	case formatOption o of
+		Nothing -> do
+			let num = length safelocations
+			showNote $ show num ++ " " ++ copiesplural num
+			pp <- ppwhereis "whereis" safelocations urls
+			unless (null safelocations) $ showLongNote pp
+			pp' <- ppwhereis "untrusted" untrustedlocations urls
+			unless (null untrustedlocations) $ showLongNote $ untrustedheader ++ pp'
+		
+			mapM_ (showRemoteUrls remotemap) urls
+		Just formatter -> liftIO $ do
+			let vs = catMaybes
+				[ fmap (("file",) . fromRawFilePath)
+					(actionItemWorkTreeFile ai)
+				] ++ Command.Find.keyVars key
+			let showformatted muuid murl = putStr $
+				Utility.Format.format formatter $
+					M.fromList $ vs ++ catMaybes
+						[ fmap ("uuid",) muuid
+						, fmap ("url",) murl
+						]
+			let showformatted' muuid
+				| Utility.Format.formatContainsVar "url" formatter =
+					forM_ (concatMap snd urls) $ 
+						showformatted muuid . Just
+				| otherwise = showformatted muuid Nothing
+			if Utility.Format.formatContainsVar "uuid" formatter
+				then forM_ locations $
+					showformatted' . Just . fromUUID
+				else showformatted' Nothing
 
 	if null safelocations then stop else next $ return True
   where
diff --git a/doc/git-annex-whereis.mdwn b/doc/git-annex-whereis.mdwn
index dd836fe8d..b6cdaf2e2 100644
--- a/doc/git-annex-whereis.mdwn
+++ b/doc/git-annex-whereis.mdwn
@@ -71,6 +71,32 @@ received from remotes.
   Messages that would normally be output to standard error are included in
   the json instead.
 
+* `--format=value`
+
+  Use custom output formatting.
+
+  The value is a format string, in which '${var}' is expanded to the
+  value of a variable. To right-justify a variable with whitespace,
+  use '${var;width}' ; to left-justify a variable, use '${var;-width}';
+  to escape unusual characters in a variable, use '${escaped_var}'
+
+  These variables are available for use in formats: file, key, uuid,
+  url, backend, bytesize, humansize, keyname, hashdirlower, hashdirmixed,
+  mtime (for the mtime field of a WORM key).
+
+  Also, '\\n' is a newline, '\\000' is a NULL, etc.
+
+  When the format contains the uuid variable, it will be expanded in turn
+  for each repository that contains the file content. For example,
+  with --format="${file} ${uuid}\\n", output will look like:
+  
+	foo 00000000-0000-0000-0000-000000000001
+	foo a7f7ddd0-9a08-11ea-ab66-8358e4209d30
+	bar a7f7ddd0-9a08-11ea-ab66-8358e4209d30
+
+  The same applies when the url variable is used and a file has multiple
+  recorded urls.
+
 # SEE ALSO
 
 [[git-annex]](1)

comment
diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_1_d3b84ee74300ebf0f010fefd7f05e51e._comment b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_1_d3b84ee74300ebf0f010fefd7f05e51e._comment
new file mode 100644
index 000000000..9818e1f0c
--- /dev/null
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files/comment_1_d3b84ee74300ebf0f010fefd7f05e51e._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-19T17:03:09Z"
+ content="""
+git is configured to filter the file through git-annex, so git does not
+need to deal with the large content of the file.
+
+But this error message seems to come from part of git that just stats the
+file, and looks at its size. So there's nothing git-annex is configuring
+wrong, and using git-lfs would likewise make git fail the same.
+
+I don't think this is a bug in git-annex. It should be reported to the git
+developers. The error comes from `xsize_t`, and according to git's commit 
+dc49cd769b5fa6b7e0114b051c34a849828a7603 it was intended to detect cases
+where git can't possibly malloc enough memory for a file, because `size_t`
+is not wide enough, compared with `off_t`.
+
+On linux amd64, both are 8. On linux i386 and arm, both are 4. So I don't
+think any usual linux systems are affected by this, only unusual systems
+that use different sizes for them.
+"""]]

diff --git a/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn b/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
index 97b4415f8..69ad9a51e 100644
--- a/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
+++ b/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
@@ -11,7 +11,7 @@ It seems this can be achieved by setting preferred content to `present` on the l
 $ git annex sync --content
 ```
 
-However, this is very slow (compared to --no-content, which is takes seconds), it seems to iterate the whole repository for presence.
+However, this is very slow (compared to --no-content, which takes seconds), it seems to iterate the whole repository for presence.
 
 I'm not too familiar with git-annex's internals, but it seems finding a sparse set of present files is already implemented efficiently:
 

diff --git a/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn b/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
index bd5b1dbbc..97b4415f8 100644
--- a/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
+++ b/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
@@ -5,7 +5,7 @@ The scenario I was trying to achieve is to by default have:
 - All files always present on the server
 - Only files added locally/pulled manually on the laptop
 
-It seems this can be achieved by setting preferred content to `present` on the laptop and then regularly calling
+It seems this can be achieved by setting preferred content to `present` on the laptop, required `*` on the server and then regularly calling
 
 ```
 $ git annex sync --content

diff --git a/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn b/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
new file mode 100644
index 000000000..bd5b1dbbc
--- /dev/null
+++ b/doc/forum/Wanted___39__present__39___makes_sync_slow_on_thin_copy_of_large_annex..mdwn
@@ -0,0 +1,22 @@
+I have a large annex (~200k files) on a server with a thin checkout on my laptop.
+
+The scenario I was trying to achieve is to by default have:
+
+- All files always present on the server
+- Only files added locally/pulled manually on the laptop
+
+It seems this can be achieved by setting preferred content to `present` on the laptop and then regularly calling
+
+```
+$ git annex sync --content
+```
+
+However, this is very slow (compared to --no-content, which is takes seconds), it seems to iterate the whole repository for presence.
+
+I'm not too familiar with git-annex's internals, but it seems finding a sparse set of present files is already implemented efficiently:
+
+```
+$ time git annex find --in=here
+```
+
+takes 5 seconds to complete on the laptop.

diff --git a/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn
new file mode 100644
index 000000000..315f6bfdd
--- /dev/null
+++ b/doc/bugs/git_annex_creds_are_not_embedded_with_newer_git-annex_clients.mdwn
@@ -0,0 +1,57 @@
+### Please describe the problem.
+With a newer version of git annex (8.20200226 vs 6.20170101) .git/annex/creds folder is not created after `git annex enableremote s3`
+With an older version 6.20170101 creds are embedded all-right.
+
+[[!format sh """
+git annex info s3:
+
+remote: s3
+type: S3
+creds: embedded in git repository (not encrypted)
+
+"""]]
+
+### What steps will reproduce the problem?
+
+This is a bit tricky, as the remote was setup long ago, god knows with which git-annex version, but after you have an S3 remote, with embedcreds=yes:
+
+run `git annex enableremote s3` with versions 8.20200226 and 6.20170101
+
+
+[[!format sh """
+# version 8.20200226
+$ git annex enableremote s3
+$ ls .git/annex/creds
+ls: cannot access '.git/annex/creds': No such file or directory
+
+# version 6.20170101
+$ git annex enableremote s3
+$ ls ../release-archive__/.git/annex/creds 
+<s3-UUID>
+
+$ git annex info s3:
+remote: s3
+type: S3
+creds: embedded in git repository (not encrypted)
+
+"""]]
+
+### What version of git-annex are you using? On what operating system?
+
+8.20200226 and 6.20170101
+Linux, Ubuntu 20.04
+
+
+### Please provide any additional information below.
+
+[[!format sh """
+# If you can, paste a complete transcript of the problem occurring here.
+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log
+
+
+# End of transcript or log.
+"""]]
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+
+

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
index 4918d5829..2f35b0913 100644
--- a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -39,6 +39,7 @@ Why does git even feel responsible to load this file?
 ### What version of git-annex are you using? On what operating system?
 
 Synology NAS
+
     git-annex version: 8.20200331-g111b747be
     build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
     dependency versions: aws-0.20 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.3 feed-1.0.1.0 ghc-8.6.5 http-client-0.5.14 persistent-sqlite-2.9.3 torrent-10000.1.1 uuid-1.3.13 yesod-1.6.0

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
index 39c382168..4918d5829 100644
--- a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -39,18 +39,17 @@ Why does git even feel responsible to load this file?
 ### What version of git-annex are you using? On what operating system?
 
 Synology NAS
-
-git-annex version: 8.20200331-g111b747be
-build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
-dependency versions: aws-0.20 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.3 feed-1.0.1.0 ghc-8.6.5 http-client-0.5.14 persistent-sqlite-2.9.3 torrent-10000.1.1 uuid-1.3.13 yesod-1.6.0
-key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL
-remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs hook external
-operating system: linux arm
-supported repository versions: 8
-upgrade supported from repository versions: 0 1 2 3 4 5 6 7
-local repository version: 8
-
-git version 2.26.1
+    git-annex version: 8.20200331-g111b747be
+    build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
+    dependency versions: aws-0.20 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.3 feed-1.0.1.0 ghc-8.6.5 http-client-0.5.14 persistent-sqlite-2.9.3 torrent-10000.1.1 uuid-1.3.13 yesod-1.6.0
+    key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL
+    remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs hook external
+    operating system: linux arm
+    supported repository versions: 8
+    upgrade supported from repository versions: 0 1 2 3 4 5 6 7
+    local repository version: 8
+
+    git version 2.26.1
 
 
 

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
index 1e92fa45b..39c382168 100644
--- a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -9,51 +9,29 @@ So how should these unlocked pointer files be hidden technically to not be index
 
 
 ### What steps will reproduce the problem?
-$ git init
-
-Initialized empty Git repository in /volume1/homes/admin/git-annex/test3/.git/
-
-$ git annex init --version 8
-
-init  (scanning for unlocked files...)
-
-ok
-
-(recording state in git...)
-
-$ ls -lah 
-
-total 12K
-
-drwxr-xr-x 3 admin users 4.0K May 16 17:00 .
-
-drwxr-xr-x 8 admin users 4.0K May 16 17:00 ..
-
-drwxr-xr-x 9 admin users 4.0K May 16 17:01 .git
-
--rw-r--r-- 1 admin users  20G May 16 17:00 output
-
-$ git annex add output
-
-add output 
-
-$ git annex sync
-
-$ git annex unlock output
-
-$ git annex status
-
-fatal: Cannot handle files this big
-
-git-annex: git status failed
-
-$ git status
-
-fatal: Cannot handle files this big
-
-$ git diff
-
-fatal: Cannot handle files this big
+    $ git init
+    Initialized empty Git repository in /volume1/homes/admin/git-annex/test3/.git/
+    $ git annex init --version 8
+    init  (scanning for unlocked files...)
+    ok
+    (recording state in git...)
+    $ ls -lah 
+    total 12K
+    drwxr-xr-x 3 admin users 4.0K May 16 17:00 .
+    drwxr-xr-x 8 admin users 4.0K May 16 17:00 ..
+    drwxr-xr-x 9 admin users 4.0K May 16 17:01 .git
+    -rw-r--r-- 1 admin users  20G May 16 17:00 output
+    $ git annex add output
+    add output 
+    $ git annex sync
+    $ git annex unlock output
+    $ git annex status
+    fatal: Cannot handle files this big
+    git-annex: git status failed
+    $ git status
+    fatal: Cannot handle files this big
+    $ git diff
+    fatal: Cannot handle files this big
 
 Why does git even feel responsible to load this file?
 

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
index 1830f614b..1e92fa45b 100644
--- a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -88,4 +88,4 @@ git version 2.26.1
 
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
 
-
+Unlocking files (with thin set to true) seems to be the perfect solution for me - I just have to understand what's going on under the hood ;)

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
index b8c821903..1830f614b 100644
--- a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -9,6 +9,9 @@ So how should these unlocked pointer files be hidden technically to not be index
 
 
 ### What steps will reproduce the problem?
+$ git init
+
+Initialized empty Git repository in /volume1/homes/admin/git-annex/test3/.git/
 
 $ git annex init --version 8
 

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
index c09dfe5e1..b8c821903 100644
--- a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -11,35 +11,52 @@ So how should these unlocked pointer files be hidden technically to not be index
 ### What steps will reproduce the problem?
 
 $ git annex init --version 8
+
 init  (scanning for unlocked files...)
+
 ok
+
 (recording state in git...)
+
 $ ls -lah 
+
 total 12K
+
 drwxr-xr-x 3 admin users 4.0K May 16 17:00 .
+
 drwxr-xr-x 8 admin users 4.0K May 16 17:00 ..
+
 drwxr-xr-x 9 admin users 4.0K May 16 17:01 .git
+
 -rw-r--r-- 1 admin users  20G May 16 17:00 output
+
 $ git annex add output
+
 add output 
 
 $ git annex sync
 
 $ git annex unlock output
+
 $ git annex status
+
 fatal: Cannot handle files this big
+
 git-annex: git status failed
 
 $ git status
+
 fatal: Cannot handle files this big
 
 $ git diff
+
 fatal: Cannot handle files this big
 
 Why does git even feel responsible to load this file?
 
 
 ### What version of git-annex are you using? On what operating system?
+
 Synology NAS
 
 git-annex version: 8.20200331-g111b747be

diff --git a/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
new file mode 100644
index 000000000..c09dfe5e1
--- /dev/null
+++ b/doc/bugs/__34__Cannot_handle_files_this_big__34___error_for_unlocked_files.mdwn
@@ -0,0 +1,71 @@
+### Please describe the problem.
+Unlocking a large file on the Synology NAS results in "Cannot handle files this big" errors with every following other git command (git status, git diff, ... and hereby git annex status/sync etc.).
+
+Unfortunately I miss the technical understanding how the pointer files are hidden from git - I've seen the smudge/clean filters though.
+
+How does it work?
+After a file is unlocked, it is physically part of the working tree and also part of the git history, so a git status/diff will naturally try to index/check that file without running the annex filter, which then results in this error message, right?
+So how should these unlocked pointer files be hidden technically to not be indexed and checked by git?
+
+
+### What steps will reproduce the problem?
+
+$ git annex init --version 8
+init  (scanning for unlocked files...)
+ok
+(recording state in git...)
+$ ls -lah 
+total 12K
+drwxr-xr-x 3 admin users 4.0K May 16 17:00 .
+drwxr-xr-x 8 admin users 4.0K May 16 17:00 ..
+drwxr-xr-x 9 admin users 4.0K May 16 17:01 .git
+-rw-r--r-- 1 admin users  20G May 16 17:00 output
+$ git annex add output
+add output 
+
+$ git annex sync
+
+$ git annex unlock output
+$ git annex status
+fatal: Cannot handle files this big
+git-annex: git status failed
+
+$ git status
+fatal: Cannot handle files this big
+
+$ git diff
+fatal: Cannot handle files this big
+
+Why does git even feel responsible to load this file?
+
+
+### What version of git-annex are you using? On what operating system?
+Synology NAS
+
+git-annex version: 8.20200331-g111b747be
+build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
+dependency versions: aws-0.20 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.3 feed-1.0.1.0 ghc-8.6.5 http-client-0.5.14 persistent-sqlite-2.9.3 torrent-10000.1.1 uuid-1.3.13 yesod-1.6.0
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs hook external
+operating system: linux arm
+supported repository versions: 8
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7
+local repository version: 8
+
+git version 2.26.1
+
+
+
+### Please provide any additional information below.
+
+[[!format sh """
+# If you can, paste a complete transcript of the problem occurring here.
+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log
+
+
+# End of transcript or log.
+"""]]
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+
+

Added a comment
diff --git a/doc/bugs/weird_bug_with_annex_unlock_with_annex.thin_true_about_hard_links/comment_4_4a7ec33d4470714c9fb4271d214b3d1f._comment b/doc/bugs/weird_bug_with_annex_unlock_with_annex.thin_true_about_hard_links/comment_4_4a7ec33d4470714c9fb4271d214b3d1f._comment
new file mode 100644
index 000000000..813c3c11f
--- /dev/null
+++ b/doc/bugs/weird_bug_with_annex_unlock_with_annex.thin_true_about_hard_links/comment_4_4a7ec33d4470714c9fb4271d214b3d1f._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="jeanpmbox-456@7222359de8d1f37a7cf25a519e8faf90a9517b50"
+ nickname="jeanpmbox-456"
+ avatar="http://cdn.libravatar.org/avatar/164eb4254c5f83d95d3e0b810ff7aab9"
+ subject="comment 4"
+ date="2020-05-15T21:21:29Z"
+ content="""
+Is there an option for git-annex to recognize hard links inside a repository?
+
+I have a repository where I want a file to be in different places but when I git-annex this file I can't preserve the hard link structure.
+"""]]

Added a comment
diff --git a/doc/bugs/windows_autostart/comment_3_393899b1630cce0dc6b12ec7d29b81ca._comment b/doc/bugs/windows_autostart/comment_3_393899b1630cce0dc6b12ec7d29b81ca._comment
new file mode 100644
index 000000000..85ac68e45
--- /dev/null
+++ b/doc/bugs/windows_autostart/comment_3_393899b1630cce0dc6b12ec7d29b81ca._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="jeanpmbox-456@7222359de8d1f37a7cf25a519e8faf90a9517b50"
+ nickname="jeanpmbox-456"
+ avatar="http://cdn.libravatar.org/avatar/164eb4254c5f83d95d3e0b810ff7aab9"
+ subject="comment 3"
+ date="2020-05-15T21:14:53Z"
+ content="""
+It came when I installed git-annex, I did not ask nor tick a box to have this script loaded at startup. I installed git-annex in a different directory but the entry which was added to the start menu did not take that into account, and pointed to the default installation directory.
+"""]]

convert renameExport to throw exception
Finishes the transition to make remote methods throw exceptions, rather
than silently hide them.
A bit on the fence about this one, because when renameExport fails,
it falls back to deleting instead, and so does the user care why it failed?
However, it did let me clean up several places in the code.
This commit was sponsored by Ethan Aubin.
diff --git a/Command/Export.hs b/Command/Export.hs
index 7754f1bfa..05158cfe3 100644
--- a/Command/Export.hs
+++ b/Command/Export.hs
@@ -396,13 +396,13 @@ startMoveFromTempName r db ek f = do
 
 performRename :: Remote -> ExportHandle -> ExportKey -> ExportLocation -> ExportLocation -> CommandPerform
 performRename r db ek src dest =
-	renameExport (exportActions r) (asKey ek) src dest >>= \case
-		Just True -> next $ cleanupRename r db ek src dest
-		Just False -> do
-			warning "rename failed; deleting instead"
+	tryNonAsync (renameExport (exportActions r) (asKey ek) src dest) >>= \case
+		Right (Just ()) -> next $ cleanupRename r db ek src dest
+		Left err -> do
+			warning $ "rename failed (" ++ show err ++ "); deleting instead"
 			fallbackdelete
-		-- Remote does not support renaming, so don't warn about it.
-		Nothing -> fallbackdelete
+		-- remote does not support renaming
+		Right Nothing -> fallbackdelete
   where
 	fallbackdelete = performUnexport r db [ek] src
 
diff --git a/Remote/Adb.hs b/Remote/Adb.hs
index 39fbc2fdb..755dbed7e 100644
--- a/Remote/Adb.hs
+++ b/Remote/Adb.hs
@@ -269,8 +269,11 @@ checkPresentExportM r serial adir _k loc = checkKey' r serial aloc
   where
 	aloc = androidExportLocation adir loc
 
-renameExportM :: AndroidSerial -> AndroidPath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe Bool)
-renameExportM serial adir _k old new = Just <$> adbShellBool serial ps
+renameExportM :: AndroidSerial -> AndroidPath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
+renameExportM serial adir _k old new = do
+	unlessM (adbShellBool serial ps) $
+		giveup "adb failed"
+	return (Just ())
   where
 	oldloc = fromAndroidPath $ androidExportLocation adir old
 	newloc = fromAndroidPath $ androidExportLocation adir new
diff --git a/Remote/Directory.hs b/Remote/Directory.hs
index 70e17256d..37218bf95 100644
--- a/Remote/Directory.hs
+++ b/Remote/Directory.hs
@@ -290,15 +290,13 @@ checkPresentExportM :: FilePath -> Key -> ExportLocation -> Annex Bool
 checkPresentExportM d _k loc =
 	checkPresentGeneric d [exportPath d loc]
 
-renameExportM :: FilePath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe Bool)
-renameExportM d _k oldloc newloc = liftIO $ Just <$> go
+renameExportM :: FilePath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
+renameExportM d _k oldloc newloc = liftIO $ do
+	createDirectoryUnder d (takeDirectory dest)
+	renameFile src dest
+	removeExportLocation d oldloc
+	return (Just ())
   where
-	go = catchBoolIO $ do
-		createDirectoryUnder d (takeDirectory dest)
-		renameFile src dest
-		removeExportLocation d oldloc
-		return True
-	
 	src = exportPath d oldloc
 	dest = exportPath d newloc
 
diff --git a/Remote/External.hs b/Remote/External.hs
index 1a819ce87..7c3ae1ef5 100644
--- a/Remote/External.hs
+++ b/Remote/External.hs
@@ -342,26 +342,18 @@ removeExportDirectoryM external dir = either giveup return =<< go
 		_ -> Nothing
 	req = REMOVEEXPORTDIRECTORY dir
 
-renameExportM :: External -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe Bool)
-renameExportM external k src dest = safely (Just False) $
-	handleRequestExport external src req k Nothing $ \resp -> case resp of
+renameExportM :: External -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
+renameExportM external k src dest = either giveup return =<< go
+  where
+	go = handleRequestExport external src req k Nothing $ \resp -> case resp of
 		RENAMEEXPORT_SUCCESS k'
-			| k' == k -> result (Just True)
+			| k' == k -> result $ Right (Just ())
 		RENAMEEXPORT_FAILURE k' 
-			| k' == k -> result (Just False)
-		UNSUPPORTED_REQUEST -> result Nothing
+			| k' == k -> result $ Left "failed to rename exported file"
+		UNSUPPORTED_REQUEST -> result (Right Nothing)
 		_ -> Nothing
-  where
 	req sk = RENAMEEXPORT sk dest
 
-safely :: a -> Annex a -> Annex a
-safely onerr a = go =<< tryNonAsync a
-  where
-	go (Right r) = return r
-	go (Left e) = do
-		toplevelWarning False (show e)
-		return onerr
-
 {- Sends a Request to the external remote, and waits for it to generate
  - a Response. That is fed into the responsehandler, which should return
  - the action to run for it (or Nothing if there's a protocol error).
diff --git a/Remote/Helper/ReadOnly.hs b/Remote/Helper/ReadOnly.hs
index 93bbb7519..71e31fdd0 100644
--- a/Remote/Helper/ReadOnly.hs
+++ b/Remote/Helper/ReadOnly.hs
@@ -62,7 +62,7 @@ readonlyRemoveExport _ _ = readonlyFail
 readonlyRemoveExportDirectory :: ExportDirectory -> Annex ()
 readonlyRemoveExportDirectory _ = readonlyFail
 
-readonlyRenameExport :: Key -> ExportLocation -> ExportLocation -> Annex (Maybe Bool)
+readonlyRenameExport :: Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
 readonlyRenameExport _ _ _ = return Nothing
 
 readonlyStoreExportWithContentIdentifier :: FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> MeterUpdate -> Annex ContentIdentifier
diff --git a/Remote/Rsync.hs b/Remote/Rsync.hs
index bf4ddc2ae..d8a9c37a4 100644
--- a/Remote/Rsync.hs
+++ b/Remote/Rsync.hs
@@ -327,7 +327,7 @@ removeExportDirectoryM o ed = removeGeneric o (allbelow d : includes d)
 		Nothing -> []
 		Just f' -> includes f'
 
-renameExportM :: RsyncOpts -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe Bool)
+renameExportM :: RsyncOpts -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
 renameExportM _ _ _ _ = return Nothing
 
 {- Rsync params to enable resumes of sending files safely,
diff --git a/Remote/S3.hs b/Remote/S3.hs
index badf64288..3e414843a 100644
--- a/Remote/S3.hs
+++ b/Remote/S3.hs
@@ -508,15 +508,14 @@ checkPresentExportS3 hv r info k loc = withS3Handle hv $ \case
 			giveup "No S3 credentials configured"
 
 -- S3 has no move primitive; copy and delete.
-renameExportS3 :: S3HandleVar -> Remote -> RemoteStateHandle -> S3Info -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe Bool)
+renameExportS3 :: S3HandleVar -> Remote -> RemoteStateHandle -> S3Info -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
 renameExportS3 hv r rs info k src dest = Just <$> go
   where
 	go = withS3Handle hv $ \case
-		Just h -> checkVersioning' info rs k $ 
-			catchNonAsync (go' h) (\_ -> return False)
-		Nothing -> do 
-			warning $ needS3Creds (uuid r)
-			return False
+		Just h -> do
+			checkVersioning info rs k
+			go' h
+		Nothing -> giveup $ needS3Creds (uuid r)
 	
 	go' h = liftIO $ runResourceT $ do
 		let co = S3.copyObject (bucket info) dstobject
@@ -525,7 +524,6 @@ renameExportS3 hv r rs info k src dest = Just <$> go
 		-- ACL is not preserved by copy.
 		void $ sendS3Handle h $ co { S3.coAcl = acl info }
 		void $ sendS3Handle h $ S3.DeleteObject srcobject (bucket info)
-		return True
 	
 	srcobject = T.pack $ bucketExportLocation info src
 	dstobject = T.pack $ bucketExportLocation info dest
@@ -1291,13 +1289,3 @@ checkVersioning info rs k
 		[] -> giveup "Remote is configured to use versioning, but no S3 version ID is recorded for this key, so it cannot safely be modified."
 		_ -> return ()
 	| otherwise = return ()
-
-checkVersioning' :: S3Info -> RemoteStateHandle -> Key -> Annex Bool -> Annex Bool
-checkVersioning' info rs k a
-	| versioning info = getS3VersionID rs k >>= \case
-		[] -> do
-			warning $ "Remote is configured to use versioning, but no S3 version ID is recorded for this key, so it cannot safely be modified."
-			return False
-		_ -> a
-	| otherwise = a
-
diff --git a/Remote/WebDAV.hs b/Remote/WebDAV.hs
index 748a8ae7f..1d6cafc9f 100644
--- a/Remote/WebDAV.hs
+++ b/Remote/WebDAV.hs
@@ -176,12 +176,10 @@ retrieveHelper loc d p = do
 		withContentM $ httpBodyRetriever d p
 
 remove :: DavHandleVar -> Remover
-remove hv k = withDavHandle' hv $ \case
-	Right dav -> liftIO $ goDAV dav $
-		-- Delete the key's whole directory, including any
-		-- legacy chunked files, etc, in a single action.
-		removeHelper (keyDir k)
-	Left e -> giveup e
+remove hv k = withDavHandle hv $ \dav -> liftIO $ goDAV dav $
+	-- Delete the key's whole directory, including any
+	-- legacy chunked files, etc, in a single action.
+	removeHelper (keyDir k)
 
 removeHelper :: DavLocation -> DAVT IO ()
 removeHelper d = do

(Diff truncated)
devblog
diff --git a/doc/devblog/day_621__back_to_normal-ish.mdwn b/doc/devblog/day_621__back_to_normal-ish.mdwn
new file mode 100644
index 000000000..535c10df2
--- /dev/null
+++ b/doc/devblog/day_621__back_to_normal-ish.mdwn
@@ -0,0 +1,14 @@
+git-annex development has been more or less back to normal for the past
+several weeks, including getting on top of most of the recent backlog.
+
+Today I'm finishing up a project that has taken half the week. The internal
+remote interface uses Bool extensively, and avoided throwing exceptions,
+and so it was not uncommon for access to a remote to fail and no reason be
+given. There have been a number of bugs about one thing or anther over the
+years, which have been fixed on an ad hoc basis without addressing the
+underlying problem. Now it's all been changed to throw exceptions, so the
+failure reason will always be displayed. Some tens of thousands of lines of
+diffs later, it's almost done.
+
+Today's work was sponsored by Graham Spencer
+[on Patreon](https://www.patreon.com/joeyh).

Added a comment: Re: Usefulness of batch key processing
diff --git a/doc/todo/git-annex-get_--batch_--key/comment_3_e3de9b4893881624d530fcdef5cd7d65._comment b/doc/todo/git-annex-get_--batch_--key/comment_3_e3de9b4893881624d530fcdef5cd7d65._comment
new file mode 100644
index 000000000..49af0be3d
--- /dev/null
+++ b/doc/todo/git-annex-get_--batch_--key/comment_3_e3de9b4893881624d530fcdef5cd7d65._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="https://christian.amsuess.com/chrysn"
+ nickname="chrysn"
+ avatar="http://christian.amsuess.com/avatar/c6c0d57d63ac88f3541522c4b21198c3c7169a665a2f2d733b4f78670322ffdc"
+ subject="Re: Usefulness of batch key processing"
+ date="2020-05-15T09:33:22Z"
+ content="""
+Concerning the filtering, I'd find a note that \"--batch-keys is mutually exclusive with filtering\" perfectly acceptable if that makes implementation easier. (Or \"only with the filtering options that apply to keys\" -- as I found that `git annex whereis --in web --key=...` does work well with the key input).
+"""]]

Added a comment: Usefulness of batch key processing
diff --git a/doc/todo/git-annex-get_--batch_--key/comment_2_033495f851735185eaad29de992ed6ab._comment b/doc/todo/git-annex-get_--batch_--key/comment_2_033495f851735185eaad29de992ed6ab._comment
new file mode 100644
index 000000000..f6aaa7488
--- /dev/null
+++ b/doc/todo/git-annex-get_--batch_--key/comment_2_033495f851735185eaad29de992ed6ab._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="https://christian.amsuess.com/chrysn"
+ nickname="chrysn"
+ avatar="http://christian.amsuess.com/avatar/c6c0d57d63ac88f3541522c4b21198c3c7169a665a2f2d733b4f78670322ffdc"
+ subject="Usefulness of batch key processing"
+ date="2020-05-15T09:21:15Z"
+ content="""
+This would be quite helpful to tools using git-annex (eg. [annex-to-web](https://gitlab.com/chrysn/annex-to-web), issue [2](https://gitlab.com/chrysn/annex-to-web/-/issues/2)), especially for short-running things like `whereis` where the launching time dominates over the processing time.
+"""]]

Added a comment: GCS using S3: removeKey when not present: FAIL
diff --git a/doc/forum/Steps_for_setting_up_Google_Cloud_Storage___40__GSC__41__/comment_1_addbedd6ee8a534c5c4f0e639c05591c._comment b/doc/forum/Steps_for_setting_up_Google_Cloud_Storage___40__GSC__41__/comment_1_addbedd6ee8a534c5c4f0e639c05591c._comment
new file mode 100644
index 000000000..31736026d
--- /dev/null
+++ b/doc/forum/Steps_for_setting_up_Google_Cloud_Storage___40__GSC__41__/comment_1_addbedd6ee8a534c5c4f0e639c05591c._comment
@@ -0,0 +1,79 @@
+[[!comment format=sh
+ username="globallyunique@da2274b36ca296fe35912b9fd7387e3a5bd17c7c"
+ nickname="globallyunique"
+ avatar="http://cdn.libravatar.org/avatar/b25877ad636e36714dbe62f9d5d0fea1"
+ subject="GCS using S3: removeKey when not present: FAIL "
+ date="2020-05-14T20:39:21Z"
+ content="""
+I mostly got it to work but running: \"git annex testremote cloud\" is all green OKs except it produces one failure for each file of: fails with the message: removeKey when not present:                      FAIL (0.35s)
+
+Annex was setup by:
+git annex initremote --force cloud      type=S3      host=storage.googleapis.com protocol=https port=80 bucket=gitannex-datalad encryption=none
+git annex wanted cloud \"anything\"
+
+testremote cloud (generating test keys...) Remote Tests
+  unavailable remote
+    removeKey:                                       OK (0.16s)
+    storeKey:                                          HttpExceptionRequest Request {
+    host                 = \"gitannex-datalad.!dne!\"
+    port                 = 443
+    secure               = True
+    requestHeaders       = [(\"Date\",\"Thu, 14 May 2020 13:31:06 GMT\"),(\"Content-Type\",\"application/octet-stream\"),(\"Authorization\",\"<REDACTED>\"),(\"x-amz-storage-class\",\"STANDARD\")]
+    path                 = \"/SHA256E-s1048576--805e60b26375f68e670a266aee7698085d9eb8ddf56f6c5ec1497f1e667384fa.this-is-a-test-key\"
+    queryString          = \"\"
+    method               = \"PUT\"
+    proxy                = Nothing
+    rawBody              = False
+    redirectCount        = 10
+    responseTimeout      = ResponseTimeoutDefault
+    requestVersion       = HTTP/1.1
+  }
+   (ConnectionFailure Network.Socket.getAddrInfo (called with preferred socket type/protocol: AddrInfo {addrFlags = [AI_ADDRCONFIG], addrFamily = AF_UNSPEC, addrSocketType = Stream, addrProtocol = 6, addrAddress = <assumed to be undefined>, addrCanonName = <assumed to be undefined>}, host name: Just \"gitannex-datalad.!dne!\", service name: Just \"443\"): does not exist (nodename nor servname provided, or not known))
+OK (0.02s)
+    checkPresent:                                    OK
+    retrieveKeyFile:                                 OK
+    retrieveKeyFileCheap:                            OK
+  key size Just 1048576; NoChunks; encryption none
+    removeKey when not present:                      FAIL (0.35s)
+      ./Command/TestRemote.hs:206:
+      failed
+    present False:                                   OK (0.13s)
+    storeKey:                                        OK (1.63s)
+    present True:                                    OK (0.15s)
+    storeKey when already present:                   OK (1.65s)
+    present True:                                    OK (0.10s)
+    retrieveKeyFile:                                 OK (0.34s)
+    fsck downloaded object:                          OK
+    retrieveKeyFile resume from 33%:                 OK (0.18s)
+    fsck downloaded object:                          OK
+    retrieveKeyFile resume from 0:                   OK (0.17s)
+    fsck downloaded object:                          OK
+    retrieveKeyFile resume from end:                 OK (0.16s)
+    fsck downloaded object:                          OK
+    removeKey when present:                          OK (0.11s)
+    present False:                                   OK (0.08s)
+  key size Just 1048576; NoChunks; encryption none
+    removeKey when not present:                      FAIL (0.30s)
+      ./Command/TestRemote.hs:206:
+      failed
+    present False:                                   OK (0.12s)
+    storeKey:                                        OK (1.60s)
+    present True:                                    OK (0.11s)
+    storeKey when already present:                   OK (2.08s)
+    present True:                                    OK (0.10s)
+    retrieveKeyFile:                                 OK (0.26s)
+    fsck downloaded object:                          OK
+    retrieveKeyFile resume from 33%:                 OK (0.19s)
+    fsck downloaded object:                          OK
+    retrieveKeyFile resume from 0:                   OK (0.16s)
+    fsck downloaded object:                          OK
+    retrieveKeyFile resume from end:                 OK (0.17s)
+    fsck downloaded object:                          OK
+    removeKey when present:                          OK (0.12s)
+    present False:                                   OK (0.12s)
+  key size Just 1048576; UnpaddedChunks 10485; encryption none
+    removeKey when not present:                      FAIL (0.33s)
+      ./Command/TestRemote.hs:206:
+      failed
+
+"""]]

diff --git a/doc/forum/Steps_for_setting_up_Google_Cloud_Storage___40__GSC__41__.mdwn b/doc/forum/Steps_for_setting_up_Google_Cloud_Storage___40__GSC__41__.mdwn
new file mode 100644
index 000000000..84fcfb4d5
--- /dev/null
+++ b/doc/forum/Steps_for_setting_up_Google_Cloud_Storage___40__GSC__41__.mdwn
@@ -0,0 +1 @@
+Are the recommended steps for setting up an annex on Google Cloud Storage (GCS) documented anywhere? The info I'm able to find seems to be from years ago. I'm struggling to get the combination of the GCS configuration to allow access and picking which of the multiple ways to initialize the annex.

diff --git a/doc/bugs/Build_failures_with_tasty_1.3.mdwn b/doc/bugs/Build_failures_with_tasty_1.3.mdwn
new file mode 100644
index 000000000..e7f33f00a
--- /dev/null
+++ b/doc/bugs/Build_failures_with_tasty_1.3.mdwn
@@ -0,0 +1,148 @@
+### Please describe the problem.
+git-annex failed to build with latest tasty 1.3
+
+### What steps will reproduce the problem?
+Build git-annex with tasty-1.3
+
+### What version of git-annex are you using? On what operating system?
+8.20200501 on Arch Linux.
+
+### Please provide any additional information below.
+    [545 of 638] Compiling Test             ( Test.hs, dist/build/git-annex/git-annex-tmp/Test.dyn_o )
+
+    Test.hs:98:13: error:
+        • Couldn't match type ‘(,) [String]’ with ‘Parser’
+          Expected type: Parser TestOptions
+            Actual type: ([String], TestOptions)
+        • In the expression:
+            TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                    <> help "preserve repositories on test failure")
+              <*> switch (long "fakessh" <> internal)
+              <*> cmdParams "non-options are for internal use only"
+          In an equation for ‘optParser’:
+              optParser
+                = TestOptions
+                    <$> suiteOptionParser ingredients (tests False True mempty)
+                    <*>
+                      switch
+                        (long "keep-failures"
+                          <> help "preserve repositories on test failure")
+                    <*> switch (long "fakessh" <> internal)
+                    <*> cmdParams "non-options are for internal use only"
+      |
+    98 | optParser = TestOptions
+      |             ^^^^^^^^^^^...
+
+    Test.hs:99:13: error:
+        • Couldn't match type ‘Parser Test.Tasty.Options.OptionSet’
+                        with ‘Test.Tasty.Options.OptionSet’
+          Expected type: ([String], Test.Tasty.Options.OptionSet)
+            Actual type: ([String], Parser Test.Tasty.Options.OptionSet)
+        • In the second argument of ‘(<$>)’, namely
+            ‘suiteOptionParser ingredients (tests False True mempty)’
+          In the first argument of ‘(<*>)’, namely
+            ‘TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)’
+          In the first argument of ‘(<*>)’, namely
+            ‘TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                      <> help "preserve repositories on test failure")’
+      |
+    99 |         <$> suiteOptionParser ingredients (tests False True mempty)
+      |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+    Test.hs:100:13: error:
+        • Couldn't match type ‘Parser’ with ‘(,) [String]’
+          Expected type: ([String], Bool)
+            Actual type: Parser Bool
+        • In the second argument of ‘(<*>)’, namely
+            ‘switch
+              (long "keep-failures"
+                  <> help "preserve repositories on test failure")’
+          In the first argument of ‘(<*>)’, namely
+            ‘TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                      <> help "preserve repositories on test failure")’
+          In the first argument of ‘(<*>)’, namely
+            ‘TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                      <> help "preserve repositories on test failure")
+              <*> switch (long "fakessh" <> internal)’
+        |
+    100 |         <*> switch
+        |             ^^^^^^...
+
+    Test.hs:104:13: error:
+        • Couldn't match type ‘Parser’ with ‘(,) [String]’
+          Expected type: ([String], Bool)
+            Actual type: Parser Bool
+        • In the second argument of ‘(<*>)’, namely
+            ‘switch (long "fakessh" <> internal)’
+          In the first argument of ‘(<*>)’, namely
+            ‘TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                      <> help "preserve repositories on test failure")
+              <*> switch (long "fakessh" <> internal)’
+          In the expression:
+            TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                    <> help "preserve repositories on test failure")
+              <*> switch (long "fakessh" <> internal)
+              <*> cmdParams "non-options are for internal use only"
+        |
+    104 |         <*> switch
+        |             ^^^^^^...
+
+    Test.hs:108:13: error:
+        • Couldn't match type ‘Parser’ with ‘(,) [String]’
+          Expected type: ([String], Types.Command.CmdParams)
+            Actual type: Parser Types.Command.CmdParams
+        • In the second argument of ‘(<*>)’, namely
+            ‘cmdParams "non-options are for internal use only"’
+          In the expression:
+            TestOptions
+              <$> suiteOptionParser ingredients (tests False True mempty)
+              <*>
+                switch
+                  (long "keep-failures"
+                    <> help "preserve repositories on test failure")
+              <*> switch (long "fakessh" <> internal)
+              <*> cmdParams "non-options are for internal use only"
+          In an equation for ‘optParser’:
+              optParser
+                = TestOptions
+                    <$> suiteOptionParser ingredients (tests False True mempty)
+                    <*>
+                      switch
+                        (long "keep-failures"
+                          <> help "preserve repositories on test failure")
+                    <*> switch (long "fakessh" <> internal)
+                    <*> cmdParams "non-options are for internal use only"
+        |
+    108 |         <*> cmdParams "non-options are for internal use only"
+        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+Yes.
+

make storeKey throw exceptions
When storing content on remote fails, always display a reason why.
Since the Storer used by special remotes already did, this mostly affects
git remotes, but not entirely. For example, if git-lfs failed to connect to
the endpoint, it used to silently return False.
diff --git a/Annex/Content.hs b/Annex/Content.hs
index 3a4899864..0e9fd9bab 100644
--- a/Annex/Content.hs
+++ b/Annex/Content.hs
@@ -584,21 +584,19 @@ unlinkAnnex key = do
 {- Runs an action to transfer an object's content.
  -
  - In some cases, it's possible for the file to change as it's being sent.
- - If this happens, runs the rollback action and returns False. The
- - rollback action should remove the data that was transferred.
+ - If this happens, runs the rollback action and throws an exception.
+ - The rollback action should remove the data that was transferred.
  -}
-sendAnnex :: Key -> Annex () -> (FilePath -> Annex Bool) -> Annex Bool
+sendAnnex :: Key -> Annex () -> (FilePath -> Annex a) -> Annex a
 sendAnnex key rollback sendobject = go =<< prepSendAnnex key
   where
-	go Nothing = return False
 	go (Just (f, checksuccess)) = do
 		r <- sendobject f
-		ifM checksuccess
-			( return r
-			, do
-				rollback
-				return False
-			)
+		unlessM checksuccess $ do
+			rollback
+			giveup "content changed while it was being sent"
+		return r
+	go Nothing = giveup "content not available to send"
 
 {- Returns a file that contains an object's content,
  - and a check to run after the transfer is complete.
diff --git a/CHANGELOG b/CHANGELOG
index ba6ec9bba..121016cc5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -26,6 +26,7 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
     the current directory.
   * Display a warning message when asked to operate on a file inside a
     directory that's a symbolic link to elsewhere.
+  * When storing content on remote fails, always display a reason why.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Command/Move.hs b/Command/Move.hs
index fd06ef01d..8aee3eb62 100644
--- a/Command/Move.hs
+++ b/Command/Move.hs
@@ -126,8 +126,12 @@ toPerform dest removewhen key afile fastcheck isthere =
 		Right False -> do
 			showAction $ "to " ++ Remote.name dest
 			ok <- notifyTransfer Upload afile $
-				upload (Remote.uuid dest) key afile stdRetry $
-					Remote.storeKey dest key afile
+				upload (Remote.uuid dest) key afile stdRetry $ \p ->
+					tryNonAsync (Remote.storeKey dest key afile p) >>= \case
+						Left e -> do
+							warning (show e)
+							return False
+						Right () -> return True
 			if ok
 				then finish False $
 					Remote.logStatus dest key InfoPresent
diff --git a/Command/TestRemote.hs b/Command/TestRemote.hs
index df4606b58..042837cf2 100644
--- a/Command/TestRemote.hs
+++ b/Command/TestRemote.hs
@@ -40,6 +40,7 @@ import "crypto-api" Crypto.Random
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import qualified Data.Map as M
+import Data.Either
 import Control.Concurrent.STM hiding (check)
 
 cmd :: Command
@@ -217,11 +218,11 @@ test runannex mkr mkk =
 	, check ("present " ++ show False) $ \r k ->
 		whenwritable r $ present r k False
 	, check "storeKey" $ \r k ->
-		whenwritable r $ store r k
+		whenwritable r $ isRight <$> tryNonAsync (store r k)
 	, check ("present " ++ show True) $ \r k ->
 		whenwritable r $ present r k True
 	, check "storeKey when already present" $ \r k ->
-		whenwritable r $ store r k
+		whenwritable r $ isRight <$> tryNonAsync (store r k)
 	, check ("present " ++ show True) $ \r k -> present r k True
 	, check "retrieveKeyFile" $ \r k -> do
 		lockContentForRemoval k removeAnnex
@@ -341,7 +342,7 @@ testUnavailable :: RunAnnex -> Annex (Maybe Remote) -> Annex Key -> [TestTree]
 testUnavailable runannex mkr mkk =
 	[ check (== Right False) "removeKey" $ \r k ->
 		Remote.removeKey r k
-	, check (== Right False) "storeKey" $ \r k -> 
+	, check isLeft "storeKey" $ \r k -> 
 		Remote.storeKey r k (AssociatedFile Nothing) nullMeterUpdate
 	, check (`notElem` [Right True, Right False]) "checkPresent" $ \r k ->
 		Remote.checkPresent r k
diff --git a/Command/TransferKey.hs b/Command/TransferKey.hs
index 8561ef82a..ee2d6b185 100644
--- a/Command/TransferKey.hs
+++ b/Command/TransferKey.hs
@@ -52,10 +52,13 @@ start o key = startingCustomOutput key $ case fromToOptions o of
 toPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
 toPerform key file remote = go Upload file $
 	upload (uuid remote) key file stdRetry $ \p -> do
-		ok <- Remote.storeKey remote key file p
-		when ok $
-			Remote.logStatus remote key InfoPresent
-		return ok
+		tryNonAsync (Remote.storeKey remote key file p) >>= \case
+			Left e -> do
+				warning (show e)
+				return False
+			Right () -> do
+				Remote.logStatus remote key InfoPresent
+				return True
 
 fromPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
 fromPerform key file remote = go Upload file $
diff --git a/Command/TransferKeys.hs b/Command/TransferKeys.hs
index f0c112ab7..1cc1fe1d3 100644
--- a/Command/TransferKeys.hs
+++ b/Command/TransferKeys.hs
@@ -38,10 +38,13 @@ start = do
 	runner (TransferRequest direction remote key file)
 		| direction == Upload = notifyTransfer direction file $
 			upload (Remote.uuid remote) key file stdRetry $ \p -> do
-				ok <- Remote.storeKey remote key file p
-				when ok $
-					Remote.logStatus remote key InfoPresent
-				return ok
+				tryNonAsync (Remote.storeKey remote key file p) >>= \case
+					Left e -> do
+						warning (show e)
+						return False
+					Right () -> do
+						Remote.logStatus remote key InfoPresent
+						return True
 		| otherwise = notifyTransfer direction file $
 			download (Remote.uuid remote) key file stdRetry $ \p ->
 				getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key $ \t -> do
diff --git a/Remote/Adb.hs b/Remote/Adb.hs
index 69b1472b5..cab25705c 100644
--- a/Remote/Adb.hs
+++ b/Remote/Adb.hs
@@ -160,7 +160,8 @@ adbSetup _ mu _ c gc = do
 store :: AndroidSerial -> AndroidPath -> Storer
 store serial adir = fileStorer $ \k src _p -> 
 	let dest = androidLocation adir k
-	in store' serial dest src
+	in unlessM (store' serial dest src) $
+		giveup "adb failed"
 
 store' :: AndroidSerial -> AndroidPath -> FilePath -> Annex Bool
 store' serial dest src = store'' serial dest src (return True)
diff --git a/Remote/BitTorrent.hs b/Remote/BitTorrent.hs
index e0191d04e..3cf426c19 100644
--- a/Remote/BitTorrent.hs
+++ b/Remote/BitTorrent.hs
@@ -111,10 +111,8 @@ downloadKey key _file dest p = unVerified $
 downloadKeyCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
 downloadKeyCheap _ _ _ = return False
 
-uploadKey :: Key -> AssociatedFile -> MeterUpdate -> Annex Bool
-uploadKey _ _ _ = do
-	warning "upload to bittorrent not supported"
-	return False
+uploadKey :: Key -> AssociatedFile -> MeterUpdate -> Annex ()
+uploadKey _ _ _ = giveup "upload to bittorrent not supported"
 
 dropKey :: Key -> Annex Bool
 dropKey k = do
diff --git a/Remote/Bup.hs b/Remote/Bup.hs
index ee6424b8f..9ea3755c9 100644
--- a/Remote/Bup.hs
+++ b/Remote/Bup.hs
@@ -156,9 +156,7 @@ store r buprepo = byteStorer $ \k b p -> do
 	showOutput -- make way for bup output
 	let cmd = proc "bup" (toCommand params)
 	quiet <- commandProgressDisabled
-	let feeder = \h -> do
-		meteredWrite p h b
-		return True
+	let feeder = \h -> meteredWrite p h b
 	liftIO $ if quiet
 		then feedWithQuietOutput createProcessSuccess cmd feeder
 		else withHandle StdinHandle createProcessSuccess cmd feeder
diff --git a/Remote/Ddar.hs b/Remote/Ddar.hs
index bc031c458..0a803f1be 100644
--- a/Remote/Ddar.hs
+++ b/Remote/Ddar.hs
@@ -127,7 +127,8 @@ store ddarrepo = fileStorer $ \k src _p -> do
 		, Param $ ddarRepoLocation ddarrepo
 		, File src
 		]
-	liftIO $ boolSystem "ddar" params
+	unlessM (liftIO $ boolSystem "ddar" params) $

(Diff truncated)
Added a comment
diff --git a/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_2_b96a4539716adf2a27930ad07c2b2b50._comment b/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_2_b96a4539716adf2a27930ad07c2b2b50._comment
new file mode 100644
index 000000000..3182a32ee
--- /dev/null
+++ b/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_2_b96a4539716adf2a27930ad07c2b2b50._comment
@@ -0,0 +1,54 @@
+[[!comment format=mdwn
+ username="Chymera"
+ avatar="http://cdn.libravatar.org/avatar/555d585d6d78c68894ac90fd1e984309"
+ subject="comment 2"
+ date="2020-05-13T04:15:53Z"
+ content="""
+oh my, so yes, this elucidates the issue quite a bit: (1) my repo registry seems to contain a lot of cruft, (2) whereis does not find the file:
+
+```
+chymera@silenthost ~/data $ git annex whereis histology/sub-6532/sub-6532_slice-15gfp_zoom-5_scene-5_transmission.tif
+whereis histology/sub-6532/sub-6532_slice-15gfp_zoom-5_scene-5_transmission.tif (1 copy)
+  	9f775012-942e-4ea7-96be-3bec8e4fcbf4 -- chymera@localhost.localdomain:~/data
+ok
+chymera@silenthost ~/data $ git annex info
+repository mode: direct
+trusted repositories: 0
+semitrusted repositories: 23
+	00000000-0000-0000-0000-000000000001 -- web
+ 	00000000-0000-0000-0000-000000000002 -- bittorrent
+ 	0db2cda2-f637-41d4-a0d2-701b105e734f -- chymera@zenbookhost:/run/media/chymera/data0/NIdata
+ 	1b16e8b5-e8ca-457b-b55f-ecc8b80e8243 -- chymera@zenbookhost:/run/media/chymera/data0/data [data0]
+ 	21038418-d6ae-4115-a64b-2aa48c37f834 -- chymera@darkhost:~/data
+ 	37e50619-7871-4b52-bb0d-dbe68314818d -- chymera@quiethost:~/NIdata
+ 	3e63db63-e218-4b5b-8c27-9ace71133731 -- chymera@quiethost:/mnt/data/data
+ 	410ad0c4-62d4-4820-a3bc-55209e8493b0 -- chymera@zenbookhost:~/data
+ 	4a86a541-33a2-4584-8db3-5e65a164a2bc -- chymera@quiethost:/run/media/chymera/data1/NIdata
+ 	5316c8a8-5321-43f8-8c4c-da938b4b4f2f -- chymera@labhost:~/data
+ 	5f721022-54a8-4833-8d33-7d3e48c929e5 -- data2
+ 	5fa05d4c-320f-43bf-9b4b-aae548675119 -- chymera@zenbookhost:~/data
+ 	5fec9ad2-83bf-4e7f-abf2-6d981fb17b4a -- chymera@zenbookhost:~///home/chymera/NIdata
+ 	6ccf6850-40f3-4130-a8de-a6a7ded9817e -- chymera@silenthost:~/data [here]
+ 	9a48528e-1595-4a9a-8c47-501fbb6b74bf -- chymera@quiethost:~/data
+ 	9f775012-942e-4ea7-96be-3bec8e4fcbf4 -- chymera@localhost.localdomain:~/data
+ 	a88e4011-c0a2-4924-a44d-66b31c5de74f -- chymera@zenhost:~/data
+ 	aeb05710-87d5-45d5-8d62-2281973d2834 -- neurohost
+ 	dd11ee2f-9b6c-4393-bc9d-df3542be52b4 -- chymera@zenhost:/zenhost/home/chymera/data
+ 	de05302b-03e7-4d91-82f5-d58ae66f863d -- chymera@neurohost:/mnt/data9/data
+ 	e56c9d76-3483-4c14-8b2e-f1aab168a9a5 -- chymera@quiethost:/run/media/chymera/data1/data
+ 	f5044a77-e912-4829-a071-b39ad187804e -- gentoo@ofmhost:~/data [ofmhost]
+ 	fd1ddddb-6a4f-49c3-b8a2-bbd3e00b934c -- quiethost
+untrusted repositories: 0
+transfers in progress: none
+available local disk space: 480.21 gigabytes (+1 megabyte reserved)
+local annex keys: 13539
+local annex size: 214.72 gigabytes
+annexed files in working tree: 15680
+size of annexed files in working tree: 215.92 gigabytes
+bloom filter size: 32 mebibytes (2.7% full)
+backend usage:
+	SHA256E: 15680
+```
+
+What can I do to (1) clean up my repo index, and (2) make sure that data0 is correctly tracked?
+"""]]

Added a comment
diff --git a/doc/bugs/Share_with_a_friend_fails/comment_2_1d5568c00a9b11a05b7fde0d2d3bc327._comment b/doc/bugs/Share_with_a_friend_fails/comment_2_1d5568c00a9b11a05b7fde0d2d3bc327._comment
new file mode 100644
index 000000000..b6c8e5539
--- /dev/null
+++ b/doc/bugs/Share_with_a_friend_fails/comment_2_1d5568c00a9b11a05b7fde0d2d3bc327._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="ryan.singer@5db89d157f0565db67eac571e2433fa96c187e32"
+ nickname="ryan.singer"
+ avatar="http://cdn.libravatar.org/avatar/a3ad31fba780a2cbebeeda3f3e627afb"
+ subject="comment 2"
+ date="2020-05-12T23:26:11Z"
+ content="""
+Seems like osascript works, but git annex doesn't seem to be using it.
+"""]]

comment
diff --git a/doc/bugs/filenames_with_dots_and_spaces_can_not_be_exported/comment_2_ebd37f03986ca7e618043f0546260503._comment b/doc/bugs/filenames_with_dots_and_spaces_can_not_be_exported/comment_2_ebd37f03986ca7e618043f0546260503._comment
new file mode 100644
index 000000000..521450c09
--- /dev/null
+++ b/doc/bugs/filenames_with_dots_and_spaces_can_not_be_exported/comment_2_ebd37f03986ca7e618043f0546260503._comment
@@ -0,0 +1,35 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2020-05-12T17:36:17Z"
+ content="""
+This is one of a larger pattern of exceptions in remote operations
+not being displayed. It should be deal with broadly, not only this case.
+
+I looked into two approaches..
+
+1. Change the remote interface to not return False, but always throw
+   exceptions on failure. Then each thing using the interface can
+   catch and display exceptions.  
+   Pro: Catch and display is more centralized, a single remote can't forget
+   to catch some exception.  
+   Con: What failed might be a command, which displays its own error
+   message. Then an exception, eg "command foo failed" would still need
+   to be thrown and displayed. (A workaround would be to add a new type of
+   exception, to be thrown in this situation, that does not get displayed.)
+
+2. Add functions like catchBoolIOAndWarn and remote modify code to use them,
+   so when exceptions are caught, they're displayed.  
+   Pro: Avoids above con. Easy to change a little at a time, easy to
+   check with grep that a remote is using that rather than catchBoolIO.
+   Con: Sometimes an exception will be caught for a reason that should
+   not result in a warning, so a remote will need to keep using catchBoolIO
+   there. That's ok when the exception is something the remote deals with
+   itself. OTOH, some actions like renameExport should probably not display
+   a warning (because when that fails, it falls back to a delete and
+   re-upload so it's not a hard failure), and which are which may not be
+   clear.
+
+I'm leaning toward #1, but without the added type of exception
+probably unless that does turn out to be worth doing in some case.
+"""]]

followup
diff --git a/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_1_8eb0b821d4ba63fa0e5bbfbca4488cb9._comment b/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_1_8eb0b821d4ba63fa0e5bbfbca4488cb9._comment
new file mode 100644
index 000000000..160346221
--- /dev/null
+++ b/doc/bugs/git_annex_can__39__t_see_connected_remote/comment_1_8eb0b821d4ba63fa0e5bbfbca4488cb9._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-12T16:43:25Z"
+ content="""
+Does the repository at /run/media/chymera/data0/data 
+have an annex.uuid of 9f775012-942e-4ea7-96be-3bec8e4fcbf4 ?
+
+Also, does that repository have the content of the file in it?
+Running ls on the file in the working tree will not tell you that.
+
+Easy way to answer both question is:
+cd to the remote and run git-annex whereis on the file
+
+(If the answer to either question is no, there's no bug.)
+"""]]

fix paste
diff --git a/doc/tips/using_Backblaze_B2.mdwn b/doc/tips/using_Backblaze_B2.mdwn
index f319e0db4..2669876cc 100644
--- a/doc/tips/using_Backblaze_B2.mdwn
+++ b/doc/tips/using_Backblaze_B2.mdwn
@@ -4,7 +4,7 @@ choices:
 * Using [[special_remotes/rclone]]  
   (Actively maintained)
 
-* Google Cloud Storage supports supports the same API as Amazon S3, so
+* Backblaze B2 supports supports the same API as Amazon S3, so
   git-annex's built-in [[S3 special remote|special_remotes/S3]] can be used
   with it. 
 

Added a comment
diff --git a/doc/forum/backblaze_s3/comment_4_bd008868a576bf09c6fa188dc8a5907c._comment b/doc/forum/backblaze_s3/comment_4_bd008868a576bf09c6fa188dc8a5907c._comment
new file mode 100644
index 000000000..ce25cb1bc
--- /dev/null
+++ b/doc/forum/backblaze_s3/comment_4_bd008868a576bf09c6fa188dc8a5907c._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="efraim@78c5af2ab57cf0d7aa23bae3dd0adb700c98217c"
+ nickname="efraim"
+ avatar="http://cdn.libravatar.org/avatar/6dc24928a791046ff66c8c7bd7a33099"
+ subject="comment 4"
+ date="2020-05-12T13:16:51Z"
+ content="""
+my remote ended up being s3.us-west-000.backblazeb2.com but I take it the us-west string can be other regions, and the 000 is 002 in their press release. The code snippet you posted looks good.
+"""]]

man pages improvements
Added some examples. Tightened up some language and removed some
unncessary duplicate documentaton.
diff --git a/doc/git-annex-add.mdwn b/doc/git-annex-add.mdwn
index ce9cd8c16..ea9d3c1db 100644
--- a/doc/git-annex-add.mdwn
+++ b/doc/git-annex-add.mdwn
@@ -29,6 +29,13 @@ supporting symlinks.)
 This command can also be used to add symbolic links, both symlinks to
 annexed content, and other symlinks.
 
+# EXAMPLES
+
+	# git annex add foo bar
+	add foo ok
+	add bar ok
+	# git commit -m added
+
 # OPTIONS
 
 * `--force`
diff --git a/doc/git-annex-drop.mdwn b/doc/git-annex-drop.mdwn
index 6b8415bf7..3b1f7707e 100644
--- a/doc/git-annex-drop.mdwn
+++ b/doc/git-annex-drop.mdwn
@@ -21,6 +21,19 @@ even if enough copies exist elsewhere. See [[git-annex-required]](1).
 With no parameters, tries to drop all annexed files in the current directory.
 Paths of files or directories to drop can be specified.
 
+# EXAMPLES
+
+	# git annex drop *.jpeg
+	drop photo1.jpg (checking origin...) ok
+	drop photo2.jpg (unsafe)
+	  Could only verify the existence of 0 out of 1 necessary copies
+
+	  Rather than dropping this file, try using: git annex move
+
+	  (Use --force to override this check, or adjust numcopies.)
+	failed
+	drop photo3.jpg (checking origin...) ok
+
 # OPTIONS
 
 * `--from=remote`
diff --git a/doc/git-annex-get.mdwn b/doc/git-annex-get.mdwn
index abe575781..28a73aa3f 100644
--- a/doc/git-annex-get.mdwn
+++ b/doc/git-annex-get.mdwn
@@ -16,6 +16,16 @@ With no parameters, gets all annexed files in the current directory whose
 content was not already present. Paths of files or directories to get can
 be specified.
 
+# EXAMPLES
+
+	# evince foo.pdf
+	error: Unable to open document foo.pdf: No such file or directory
+	# ls foo.pdf
+	foo.pdf@
+	# git annex get foo.pdf
+	get foo.pdf (from origin..) ok
+	# evince foo.pdf
+
 # OPTIONS
 
 * `--auto`
diff --git a/doc/git-annex-init.mdwn b/doc/git-annex-init.mdwn
index 966b03938..c11edd577 100644
--- a/doc/git-annex-init.mdwn
+++ b/doc/git-annex-init.mdwn
@@ -29,6 +29,15 @@ in a repository. This is useful for repositories that have a policy
 reason not to use git-annex. The content of the file will be displayed
 to the user who tries to run git-annex init.
 
+# EXAMPLES
+
+	# git annex add foo
+	git-annex: First run: git-annex init
+	# git annex init
+	init ok
+	# git annex add foo
+	add foo ok
+
 # OPTIONS
 
 * `--version=N`
diff --git a/doc/git-annex-lock.mdwn b/doc/git-annex-lock.mdwn
index c13654dbe..202faf6a4 100644
--- a/doc/git-annex-lock.mdwn
+++ b/doc/git-annex-lock.mdwn
@@ -1,6 +1,6 @@
 # NAME
 
-git-annex lock - undo unlock command
+git-annex lock - lock files to prevent modification
 
 # SYNOPSIS
 
@@ -8,8 +8,13 @@ git annex lock `[path ...]`
 
 # DESCRIPTION
 
-Use this to undo an unlock command if you don't want to modify
-the files any longer, or have made modifications you want to discard.
+Lock the specified annexed files, to prevent them from being modified.
+When no files are specified, all annexed files in the current directory are
+locked.
+
+Locking a file changes how it is stored in the git repository (from a
+pointer file to a symlink), so this command will make a change that you
+can commit.
 
 # OPTIONS
 
diff --git a/doc/git-annex-unlock.mdwn b/doc/git-annex-unlock.mdwn
index 3dea02b3e..b410c880b 100644
--- a/doc/git-annex-unlock.mdwn
+++ b/doc/git-annex-unlock.mdwn
@@ -9,8 +9,8 @@ git annex unlock `[path ...]`
 # DESCRIPTION
 
 Normally, the content of annexed files is protected from being changed.
-Unlocking an annexed file allows it to be modified. This replaces the
-symlink for each specified file with the file's content.
+Unlocking an annexed file allows it to be modified. When no files are
+specified, all annexed files in the current directory are unlocked.
 
 Unlocking a file changes how it is stored in the git repository (from a
 symlink to a pointer file), so this command will make a change that you
@@ -32,6 +32,16 @@ system.) While this can save considerable disk space, any modification made
 to a file will cause the old version of the file to be lost from the local
 repository. So, enable annex.thin with care.
 
+# EXAMPLES
+
+	# git annex unlock disk-image
+	# git commit -m "unlocked to allow VM to make changes as it runs"
+
+	# git annex unlock photo.jpg
+	# gimp photo.jpg
+	# git annex lock photo.jpg
+	# git commit -m "redeye removal"
+
 # OPTIONS
 
 * file matching options
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 7925d2bd8..3703bcd15 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -54,12 +54,6 @@ content from the key-value store.
 
 # COMMONLY USED COMMANDS
 
-Like many git commands, git-annex can be passed a path that
-is either a file or a directory. In the latter case it acts on all relevant
-files in the directory. When no path is specified, most git-annex commands
-default to acting on all relevant files in the current directory (and
-subdirectories).
-
 * `help`
 
   Display built-in help.
@@ -68,8 +62,7 @@ subdirectories).
 
 * `add [path ...]`
 
-  Adds files in the path to the annex. If no path is specified, adds
-  files from the current directory and below. 
+  Adds files to the annex.
   
   See [[git-annex-add]](1) for details.
 
@@ -1821,9 +1814,9 @@ These environment variables are used by git-annex when set:
   variable can confuse git-annex's book-keeping, sometimes in ways that
   `git annex fsck` is unable to repair.
 
-Some special remotes use additional environment variables
-for authentication etc. For example, `AWS_ACCESS_KEY_ID`
-and `GIT_ANNEX_P2P_AUTHTOKEN`. See special remote documentation.
+* Some special remotes use additional environment variables
+  for authentication etc. For example, `AWS_ACCESS_KEY_ID`
+  and `GIT_ANNEX_P2P_AUTHTOKEN`. See special remote documentation.
 
 # FILES
 

diff --git a/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn b/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn
new file mode 100644
index 000000000..6212eb2cb
--- /dev/null
+++ b/doc/bugs/git_annex_can__39__t_see_connected_remote.mdwn
@@ -0,0 +1,47 @@
+### Please describe the problem.
+
+Git annex won't pull from available remote
+
+### What steps will reproduce the problem?
+
+See full log demonstrating the issue. The file is accessible from a remote which is recorded, both remotes are synced, but instead it attempts a nonexistent remote download.
+
+```
+chymera@silenthost ~/data $ git annex get histology/sub-6532/sub-6532_slice-15gfp_zoom-5_scene-5_transmission.tif
+get histology/sub-6532/sub-6532_slice-15gfp_zoom-5_scene-5_transmission.tif (not available)
+  Try making some of these repositories available:
+  	9f775012-942e-4ea7-96be-3bec8e4fcbf4 -- chymera@localhost.localdomain:~/data
+failed
+git-annex: get: 1 failed
+chymera@silenthost ~/data $ git remote -v
+data0	/run/media/chymera/data0/data (fetch)
+data0	/run/media/chymera/data0/data (push)
+data1	/run/media/chymera/data1/data (fetch)
+data1	/run/media/chymera/data1/data (push)
+ofmhost	ofmhost:data (fetch)
+ofmhost	ofmhost:data (push)
+chymera@silenthost ~/data $ git log | head -1
+commit 6f7b889c3487fb6dacbfd7a3a6fa8c55ea3ed274
+chymera@silenthost ~/data $ pushd /run/media/chymera/data0/data
+/run/media/chymera/data0/data ~/data
+chymera@silenthost /run/media/chymera/data0/data $ git remote -v
+data1	/run/media/chymera/data1/data (fetch)
+data1	/run/media/chymera/data1/data (push)
+ofmhost	ofmhost:data (fetch)
+ofmhost	ofmhost:data (push)
+quiethost	/quiethost/home/chymera/data/ (fetch)
+quiethost	/quiethost/home/chymera/data/ (push)
+silenthost	/silenthost/home/chymera/data (fetch)
+silenthost	/silenthost/home/chymera/data (push)
+chymera@silenthost /run/media/chymera/data0/data $ ls -lah histology/sub-6532/sub-6532_slice-15gfp_zoom-5_scene-5_transmission.tif
+-rwxrwxrwx 1 chymera chymera 192 May 12 02:41 histology/sub-6532/sub-6532_slice-15gfp_zoom-5_scene-5_transmission.tif
+chymera@silenthost /run/media/chymera/data0/data $ git log | head -1
+commit 6f7b889c3487fb6dacbfd7a3a6fa8c55ea3ed274
+```
+
+### What version of git-annex are you using? On what operating system?
+=git-annex-6.20170818-r1 on Gentoo Linux
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+I keep coming back to it, it's given me a steady stream of frustration and satisfaction for over 5 years.
+

Display a warning message when asked to operate on a file inside a directory that's a symbolic link to elsewhere
This relicates git's behavior. It adds a few stat calls for the command
line parameters, so there is some minor slowdown, but even with thousands
of parameters it will not be very noticable, and git does the same statting
in similar circumstances.
Note that this does not prevent eg "git annex add symlink"; the symlink
will be added to git as usual. And "git annex find symlink" will silently
list nothing as well. It's only "symlink/foo" or "subdir/symlink/foo" that
triggers the warning.
diff --git a/CHANGELOG b/CHANGELOG
index 3062587c1..ba6ec9bba 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,8 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
     without any sanitization, but will fail if the filename has an obvious
     security problem like using an escape sequence or trying to escape
     the current directory.
+  * Display a warning message when asked to operate on a file inside a
+    directory that's a symbolic link to elsewhere.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/CmdLine/Seek.hs b/CmdLine/Seek.hs
index 6f035fdcb..77c3bd0e2 100644
--- a/CmdLine/Seek.hs
+++ b/CmdLine/Seek.hs
@@ -243,28 +243,47 @@ newtype WorkTreeItem = WorkTreeItem FilePath
 -- seeking for such files.
 newtype AllowHidden = AllowHidden Bool
 
--- Many git commands seek work tree items matching some criteria,
+-- Many git commands like ls-files seek work tree items matching some criteria,
 -- and silently skip over anything that does not exist. But users expect
 -- an error message when one of the files they provided as a command-line
 -- parameter doesn't exist, so this checks that each exists.
+--
+-- Also, when two directories are symlinked, referring to a file
+-- inside the symlinked directory will be silently skipped by git commands
+-- like ls-files. But, the user would be surprised for it to be skipped, so
+-- check if the parent directories are symlinks.
 workTreeItems :: CmdParams -> Annex [WorkTreeItem]
 workTreeItems = workTreeItems' (AllowHidden False)
 
 workTreeItems' :: AllowHidden -> CmdParams -> Annex [WorkTreeItem]
 workTreeItems' (AllowHidden allowhidden) ps = do
 	currbranch <- getCurrentBranch
-	forM_ ps $ \p ->
-		unlessM (exists p <||> hidden currbranch p) $ do
-			toplevelWarning False (p ++ " not found")
-			Annex.incError
+	forM_ ps $ \p -> do
+		relf <- liftIO $ relPathCwdToFile p
+		ifM (not <$> (exists p <||> hidden currbranch relf))
+			( prob (p ++ " not found")
+			, whenM (viasymlink (upFrom relf)) $
+				prob (p ++ " is beyond a symbolic link")
+			)
 	return (map (WorkTreeItem) ps)
   where
 	exists p = isJust <$> liftIO (catchMaybeIO $ getSymbolicLinkStatus p)
-	hidden currbranch p
-		| allowhidden = do
-			f <- liftIO $ relPathCwdToFile p
-			isJust <$> catObjectMetaDataHidden (toRawFilePath f) currbranch
+
+	viasymlink Nothing = return False
+	viasymlink (Just p) =
+		ifM (liftIO $ isSymbolicLink <$> getSymbolicLinkStatus p)
+			( return True
+			, viasymlink (upFrom p)
+			)
+
+	hidden currbranch f
+		| allowhidden = isJust
+			<$> catObjectMetaDataHidden (toRawFilePath f) currbranch
 		| otherwise = return False
 
+	prob msg = do
+		toplevelWarning False msg
+		Annex.incError
+	
 notSymlink :: RawFilePath -> IO Bool
 notSymlink f = liftIO $ not . isSymbolicLink <$> R.getSymbolicLinkStatus f
diff --git a/Utility/Path.hs b/Utility/Path.hs
index c1137d792..b66e12714 100644
--- a/Utility/Path.hs
+++ b/Utility/Path.hs
@@ -88,7 +88,7 @@ parentDir :: FilePath -> FilePath
 parentDir = takeDirectory . dropTrailingPathSeparator
 
 {- Just the parent directory of a path, or Nothing if the path has no
-- parent (ie for "/" or ".") -}
+- parent (ie for "/" or "." or "foo") -}
 upFrom :: FilePath -> Maybe FilePath
 upFrom dir
 	| length dirs < 2 = Nothing
diff --git a/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn b/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn
index 0ca46efe8..b7893cc56 100644
--- a/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn
+++ b/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn
@@ -8,3 +8,5 @@ This happens because git ls-files doesn't list the file, but then I think
 the code that handles erroring if a file that does not exist is specified
 doesn't catch it because the file does exist, it's just behind the symlink.
 --[[Joey]]
+
+> [[fixed|done]] --[[Joey]]

addurl --preserve-filename for other remotes
Finishing work begun in 695206066548b3cafc46d03e32b164a916aa00e7
Also, truncate filenames provided by other remotes if they're too long,
when --preserve-filename is not used. That seems to have been omitted
before by accident.
diff --git a/Command/AddUrl.hs b/Command/AddUrl.hs
index e25a420b9..ede22bebb 100644
--- a/Command/AddUrl.hs
+++ b/Command/AddUrl.hs
@@ -136,14 +136,16 @@ checkUrl addunlockedmatcher r o u = do
 	go _ (Left e) = void $ commandAction $ startingAddUrl u o $ do
 		warning (show e)
 		next $ return False
-	go deffile (Right (UrlContents sz f)) = do
-		let f = adjustFile o (fromMaybe (maybe deffile sanitizeFilePath mf) (fileOption (downloadOptions o)))
-		void $ commandAction $ startRemote addunlockedmatcher r o f u sz
+	go deffile (Right (UrlContents sz mf)) = do
+		f <- maybe (pure deffile) (sanitizeOrPreserveFilePath o) mf
+		let f' = adjustFile o (fromMaybe f (fileOption (downloadOptions o)))
+		void $ commandAction $ startRemote addunlockedmatcher r o f' u sz
 	go deffile (Right (UrlMulti l)) = case fileOption (downloadOptions o) of
 		Nothing ->
 			forM_ l $ \(u', sz, f) -> do
-				let f' = adjustFile o (deffile </> sanitizeFilePath f)
-				void $ commandAction $ startRemote addunlockedmatcher r o f' u' sz
+				f' <- sanitizeOrPreserveFilePath o f
+				let f'' = adjustFile o (deffile </> sanitizeFilePath f')
+				void $ commandAction $ startRemote addunlockedmatcher r o f'' u' sz
 		Just f -> case l of
 			[] -> noop
 			((u',sz,_):[]) -> do
@@ -215,20 +217,26 @@ startWeb addunlockedmatcher o urlstring = go $ fromMaybe bad $ parseURI urlstrin
 		file <- adjustFile o <$> case fileOption (downloadOptions o) of
 			Just f -> pure f
 			Nothing -> case Url.urlSuggestedFile urlinfo of
-				Just sf | not (null sf) -> if preserveFilenameOption (downloadOptions o)
-					then do
-						checkPreserveFileNameSecurity sf
-						return sf
-					else do
-						let f = truncateFilePath pathmax $
-							sanitizeFilePath sf
-						ifM (liftIO $ doesFileExist f <||> doesDirectoryExist f)
+				Just sf -> do
+					f <- sanitizeOrPreserveFilePath o sf
+					if preserveFilenameOption (downloadOptions o)
+						then pure f
+						else ifM (liftIO $ doesFileExist f <||> doesDirectoryExist f)
 							( pure $ url2file url (pathdepthOption o) pathmax
 							, pure f
 							)
 				_ -> pure $ url2file url (pathdepthOption o) pathmax
 		performWeb addunlockedmatcher o urlstring file urlinfo
 
+sanitizeOrPreserveFilePath :: AddUrlOptions -> FilePath -> Annex FilePath
+sanitizeOrPreserveFilePath o f
+	| preserveFilenameOption (downloadOptions o) && not (null f) = do
+		checkPreserveFileNameSecurity f
+		return f
+	| otherwise = do
+		pathmax <- liftIO $ fileNameLengthLimit "."
+		return $ truncateFilePath pathmax $ sanitizeFilePath f
+
 -- sanitizeFilePath avoids all these security problems
 -- (and probably others, but at least this catches the most egrarious ones).
 checkPreserveFileNameSecurity :: FilePath -> Annex ()
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn
index 390160b92..b6098127a 100644
--- a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn
@@ -45,3 +45,5 @@ git-annex version: 7.20190708+git9-gfa3524b95-1~ndall+1
 
 [[!meta author=yoh]]
 [[!tag projects/dandi]]
+
+> [[done]] --[[Joey]]
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment
index 85a274a22..99ebacee6 100644
--- a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment
@@ -3,10 +3,12 @@
  subject="""comment 5"""
  date="2020-05-11T17:20:07Z"
  content="""
-I agree that it may as well allow non-leading '-'.
+I agree that it may as well allow non-leading '-'. But, if you are relying
+on getting the unsanitized filename generally, you should use
+--preserve-filename
 
 Web browsers do do some santization, particulary of '/'.
-Chrome removes leading "." as well. Often files are downloaded to locations
+Chrome removes leading "." as well. Often files are downloaded
 without the user confirming it. I suspect there is enough insecurity
 in that area that someone could make a living injecting bitcoin miners into
 dotfiles.

addurl, importfeed: Allow '-' in filenames, as long as it's not the first character
diff --git a/Annex/UntrustedFilePath.hs b/Annex/UntrustedFilePath.hs
index 29c02709f..c843e8042 100644
--- a/Annex/UntrustedFilePath.hs
+++ b/Annex/UntrustedFilePath.hs
@@ -15,25 +15,28 @@ import System.FilePath
  - sane FilePath.
  -
  - All spaces and punctuation and other wacky stuff are replaced
- - with '_', except for '.'
+ - with '_', except for '.' and '-'
  -
  - "../" becomes ".._", which is safe.
  - "/foo" becomes "_foo", which is safe.
  - "c:foo" becomes "c_foo", which is safe even on windows.
  - 
- - Leading '.' is also replaced with '_', so ".git/foo" becomes "_git_foo"
- - and so no dotfiles that might control a program are inadvertently created.
+ - Leading '.' and '-' are also replaced with '_', so
+ - so no dotfiles that might control a program are inadvertently created,
+ - and to avoid filenames being treated as options to commands the user
+ - might run.
  -}
 sanitizeFilePath :: String -> FilePath
-sanitizeFilePath = leadingdot . map sanitize
+sanitizeFilePath = leading . map sanitize
   where
 	sanitize c
-		| c == '.' = c
+		| c == '.' || c == '-' = c
 		| isSpace c || isPunctuation c || isSymbol c || isControl c || c == '/' = '_'
 		| otherwise = c
 
-	leadingdot ('.':s) = '_':s
-	leadingdot s = s
+	leading ('.':s) = '_':s
+	leading ('-':s) = '_':s
+	leading s = s
 
 escapeSequenceInFilePath :: FilePath -> Bool
 escapeSequenceInFilePath f = '\ESC' `elem` f
diff --git a/CHANGELOG b/CHANGELOG
index ad4d9ad3c..3062587c1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -18,8 +18,12 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
     autoenable of such remotes without forcing again.
   * addurl, importfeed: Avoid adding filenames with leading '.', instead
     it will be replaced with '_'.
+  * addurl, importfeed: Allow '-' in filenames, as long as it's not the
+    first character.
   * addurl --preserve-filename: New option, uses server-provided filename
-    without any sanitization, but with some security checking.
+    without any sanitization, but will fail if the filename has an obvious
+    security problem like using an escape sequence or trying to escape
+    the current directory.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment
new file mode 100644
index 000000000..85a274a22
--- /dev/null
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_5_fad1fe49c2c545aeeb388176d2f5a893._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2020-05-11T17:20:07Z"
+ content="""
+I agree that it may as well allow non-leading '-'.
+
+Web browsers do do some santization, particulary of '/'.
+Chrome removes leading "." as well. Often files are downloaded to locations
+without the user confirming it. I suspect there is enough insecurity
+in that area that someone could make a living injecting bitcoin miners into
+dotfiles.
+"""]]

followup
diff --git a/doc/forum/backblaze_s3/comment_3_55362a91c4592775994999a843e648dc._comment b/doc/forum/backblaze_s3/comment_3_55362a91c4592775994999a843e648dc._comment
new file mode 100644
index 000000000..767dfa91c
--- /dev/null
+++ b/doc/forum/backblaze_s3/comment_3_55362a91c4592775994999a843e648dc._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2020-05-11T17:04:08Z"
+ content="""
+Thanks for verifying it works. I've updated [[tips/using_Backblaze_B2]] to
+mention this alternative, hopefully I got the config right. (Is the
+endpoint always the same?)
+"""]]
diff --git a/doc/tips/using_Backblaze_B2.mdwn b/doc/tips/using_Backblaze_B2.mdwn
index f4173aefb..f319e0db4 100644
--- a/doc/tips/using_Backblaze_B2.mdwn
+++ b/doc/tips/using_Backblaze_B2.mdwn
@@ -1,8 +1,23 @@
-For using Backblaze B2 as a special remote, there are currently two
+For using Backblaze B2 as a special remote, there are currently three
 choices:
 
 * Using [[special_remotes/rclone]]  
   (Actively maintained)
+
+* Google Cloud Storage supports supports the same API as Amazon S3, so
+  git-annex's built-in [[S3 special remote|special_remotes/S3]] can be used
+  with it. 
+
+  However, it needs S3 version 4 signatures, which are only supported by
+  git-annex 8.20200508 and newer.
+
+  Here is how to set up the special remote:
+
+        git annex initremote backblaze type=S3 signature=v4 host=$endpoint bucket=$bucketid protocol=https
+
+  Remember to replace $endpoint with the actual backblaze endpoint and $bucketid with
+  the bucketid.
+
 * A dedicated special remote, <https://github.com/encryptio/git-annex-remote-b2>  
   (Last updated 2016)
 

fix name of option
diff --git a/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment b/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment
index 71303b530..bfdb4b36a 100644
--- a/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment
+++ b/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment
@@ -3,7 +3,7 @@
  subject="""V4"""
  date="2020-05-07T16:49:05Z"
  content="""
-@bec.watson, I've now added a way to use V4 authentication, the authentication=v4
+@bec.watson, I've now added a way to use V4 authentication, the signature=v4
 option. 
 
 Please file a bug report if it still doesn't work.

response
diff --git a/doc/forum/read_directly_from_annex/comment_1_d8c4a60a672e60f89d6e57e515ef86cd._comment b/doc/forum/read_directly_from_annex/comment_1_d8c4a60a672e60f89d6e57e515ef86cd._comment
new file mode 100644
index 000000000..1f6241577
--- /dev/null
+++ b/doc/forum/read_directly_from_annex/comment_1_d8c4a60a672e60f89d6e57e515ef86cd._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-11T16:50:25Z"
+ content="""
+If the GCS remote is not configured to encrypt or chunk the files
+stored in it, they can be accessed by other things than git-annex, but
+the names of the files will be the git-annex keys (eg their hash),
+which may or may not work for what you're processing them with.
+
+If the thing you're processing them with needs to operate on
+the original filenames, you need to use a remote configured with
+exporttree=yes. Then you can use `git annex export master --to remote`
+to make the remote contain a copy of the tree of files in your master
+branch.
+
+Not all special remotes support that feature. For GCS, there is one
+option that does, using the S3 interface to GCS. (rclone and gcsannex do
+not support exporttree)
+"""]]

comments
diff --git a/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles/comment_1_263bfea4cae5a612de1761b3c3fc32b8._comment b/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles/comment_1_263bfea4cae5a612de1761b3c3fc32b8._comment
new file mode 100644
index 000000000..7d6dcfd31
--- /dev/null
+++ b/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles/comment_1_263bfea4cae5a612de1761b3c3fc32b8._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-11T16:31:58Z"
+ content="""
+I think it's quite likely that most people consider files in dotdirs to be
+dotfiles, most of the time. (.git/index is clearly not a dotfile,
+.git/config probably is) The exact semantics of it are vague enough that
+it's probably better to not consider them when it comes to this bug report.
+
+The actual bug is not about whether .foo/bar is a dotfile, but about
+inconsistent behavior adding it.
+
+Avoiding treating them as dotfiles, even if they're broadly understood as
+such would resolve the inconsistency.
+
+Otoh, the inconsistency only arises when run inside a dot directory,
+which is probably a fairly rare thing to do.
+"""]]
diff --git a/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles/comment_2_6fbd20761f9388c04fa13b38af2354d9._comment b/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles/comment_2_6fbd20761f9388c04fa13b38af2354d9._comment
new file mode 100644
index 000000000..c7cb0f845
--- /dev/null
+++ b/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles/comment_2_6fbd20761f9388c04fa13b38af2354d9._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2020-05-11T16:40:46Z"
+ content="""
+I'm also reluctant to start another behavior change in this area, there has
+been more than enough drama around dotfile handling recently.
+
+At least the behavior change would only result in small files that users
+want to store in git being annexed, rather than large files being
+unexpectedly put in git.
+
+It would also be possible for users to get back the current behavior if
+desired by configuring annex.dotfiles and annex.largefiles.
+
+Also as far as the priority of this goes, I think that the number of
+dotdirs that contain files that get version controlled at all is probably
+quite small, excluding version controlling of HOME.
+"""]]

bug
diff --git a/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn b/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn
new file mode 100644
index 000000000..0ca46efe8
--- /dev/null
+++ b/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn
@@ -0,0 +1,10 @@
+If foo is a symlink to bar, and foo/file exists, then `git annex add bar/file`
+silently does nothing. So do other commands if the file is already annexed.
+
+git's behavior on these is to complain that it's "beyond a symbolic link"
+and fail.
+
+This happens because git ls-files doesn't list the file, but then I think
+the code that handles erroring if a file that does not exist is specified
+doesn't catch it because the file does exist, it's just behind the symlink.
+--[[Joey]]

Added a comment
diff --git a/doc/forum/backblaze_s3/comment_2_5f1407460b6a56a8e267f8eecf4427aa._comment b/doc/forum/backblaze_s3/comment_2_5f1407460b6a56a8e267f8eecf4427aa._comment
new file mode 100644
index 000000000..5dd6a79ee
--- /dev/null
+++ b/doc/forum/backblaze_s3/comment_2_5f1407460b6a56a8e267f8eecf4427aa._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="efraim@78c5af2ab57cf0d7aa23bae3dd0adb700c98217c"
+ nickname="efraim"
+ avatar="http://cdn.libravatar.org/avatar/6dc24928a791046ff66c8c7bd7a33099"
+ subject="comment 2"
+ date="2020-05-11T11:29:34Z"
+ content="""
+I rebuilt git-annex with the new signature v4 patch and I got it to work.
+
+I had to create a new application key that wasn't tied to a bucket or else I would get an 'access denied' error. I didn't set any prefix on the files uploaded.
+
+AWS_ACCESS_KEY_ID=keyID AWS_SECRET_ACCESS_KEY=applicationKey git-annex initremote backblaze type=S3 host=S3-endpoint bucket=bucketID protocol=https signature=v4
+
+This created a new bucket with the same bucketID as the one I previously created and intended to use, and with the name equal to the bucketID
+
+I suspect if I had done bucket=bucketName and not bucketID I could've used a bucket specific key but now that it's set up it's not worth it to me to try to change it.
+"""]]

Added a comment
diff --git a/doc/special_remotes/S3/comment_35_a141196a77d77cc6e130185dbf01e48b._comment b/doc/special_remotes/S3/comment_35_a141196a77d77cc6e130185dbf01e48b._comment
new file mode 100644
index 000000000..e00c23eff
--- /dev/null
+++ b/doc/special_remotes/S3/comment_35_a141196a77d77cc6e130185dbf01e48b._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 35"
+ date="2020-05-10T16:30:51Z"
+ content="""
+> I don't want to enable versioning since that permanently loses the chance of dropping any objects (even if they're stored elsewhere)
+
+I believe it is in principle [possible to remove object versions](https://docs.aws.amazon.com/cli/latest/reference/s3api/delete-object.html) from S3 and/or completely wipe out an object with all of its versions (so it wouldn't be just a DeleteMarker added as the most recent version).  So in principle git-annex could (if doesn't already, didn't check) delete previous versions in a versioned bucket upon `drop`.
+"""]]

Added a comment
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_4_a32f922bb12d6cfd96c5116b20cff828._comment b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_4_a32f922bb12d6cfd96c5116b20cff828._comment
new file mode 100644
index 000000000..e10003390
--- /dev/null
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_4_a32f922bb12d6cfd96c5116b20cff828._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 4"
+ date="2020-05-09T22:10:43Z"
+ content="""
+> If the filename contains an ANSI escape sequence, it could potentially lead to a security hole.
+> ... As could a filename that contains a newline, which will break large quantities of shell pipelines. 
+
+IMHO those indeed are ok to target for sanitization
+
+> Or if the filename starts with \"-\" it could be somewhere between a possible security hole and just very annoying to work with.
+
+So why not to sanitize it only at the beginning of the filename?  
+`-` is a very common and a safe character to use within filename. For that matter we VERY frequently use `-` in filenames. It even became part of our BIDS standard in neuroimaging: https://bids-specification.readthedocs.io where we separate `_key` from `value`, e.g.in ` .  I really do not see why git-annex should so aggressively sanitize filenames as replacing \"-\" within filenames -- it makes nothing more secure or convenient.
+
+> While generally git repos can have these problems with files in them too, the exposure seems larger when talking to some random web server than when pulling from a repo.
+
+Well, not sure about ansi characters and new line symbols, but typically files are saved by the browsers with the name suggested by the server.
+"""]]

diff --git a/doc/forum/read_directly_from_annex.mdwn b/doc/forum/read_directly_from_annex.mdwn
new file mode 100644
index 000000000..11a134f22
--- /dev/null
+++ b/doc/forum/read_directly_from_annex.mdwn
@@ -0,0 +1 @@
+I want to store my annex on google cloud storage (GCS) and load files from the annex on GCS directly into Big Query for processing. I'm planning on using DataLad's gitannex features. I'm thinking this kind of approach is needed to avoid the overhead of downloading to the server where the Datalad git repo is running and the need for space to store it on the regular file system.  Is anything like this possible? 

diff --git a/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles.mdwn b/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles.mdwn
new file mode 100644
index 000000000..353fbdd1d
--- /dev/null
+++ b/doc/bugs/add__58___inconsistently_treats_files_in_dotdirs_as_dotfiles.mdwn
@@ -0,0 +1,103 @@
+This is an upstream resubmission of [Debian bug #959506](https://bugs.debian.org/959506).
+
+### Please describe the problem.
+
+As of v8, git-annex divides files into “large” and “non-large” files, the
+former of which are supposed to be automatically added to the annex and the
+latter to vanilla git when running `git annex add`. git-annex uses the
+configuration option `annex.largefiles`, a file matching expression, to
+categorize files as “large”; all other files end up as “non-large”.
+
+Furthermore, git-annex always treats “dotfiles” as “non-large”, without
+consulting `annex.largefiles`. Setting the configuration option
+`annex.dotfiles` (false by default) makes git-annex use `annex.largefiles`
+to also categorize “dotfiles”.
+
+The manual never defines which files are considered “dotfiles”, therefore
+I am assuming a definition of “a dotfile is a non-directory file whose
+basename begins with an ASCII period”. git-annex however will treat any file
+in any directory as a dotfile – i.e., it will ignore `annex.largefiles` and
+always add the file to vanilla git, unless `annex.dotfiles` is set to true
+– as long as the relative pathname to the file begins with an ASCII period,
+e.g. `.foo/bar.txt` (which is *not* a dotfile according to the assumed
+definition above). git-annex will further cease treating the same file as
+a dotfile if the relative pathname no longer begins with an ASCII period,
+e.g. because the working directory has been changed.
+
+I expect git-annex to distinguish between dotfiles and non-dotfiles solely
+by looking at the file's basename, even if the relative path to the file
+begins with a dot. I also expect `annex.dotfiles` to have no influence
+whatsoever on files whose basename doesn't begin with an ASCII period, even
+if the containing directory does. git-annex's *actual* behavior is highly
+counter-intuitive to the notion that being a dotfile is a property of the
+file's (base-)name. Due to the lack of definition of dotfiles in the manual,
+it is unclear to me whether this is intended (but in my opinion quirky)
+behavior, or rather a bug.
+
+### What steps will reproduce the problem?
+
+1.  Set up a repository for use with git-annex. Leave `annex.dotfiles` at
+    its default value (`false`), and `annex.largefiles` unset.
+
+2.  Create files `bar1`, `bar2` and `bar3` within a directory `.foo`. What
+    matters is that `.foo` begins with a period, `bar1` etc. don't.
+
+3.  Run `git annex add .foo/bar1`. git-annex will have forced the file into
+    vanilla git as a “non-large” file, because it is recognized as
+    a “dotfile”. But `bar1` is not a dotfile because it does not begin with
+    a period.
+
+4.  (Optional.) Set `annex.dotfiles` to `true` and run `git annex add
+    .foo/bar2`. The file is added to the annex. In conjunction with step 3,
+    this shows that git-annex really does apply the `annex.dotfiles` setting
+    to files such as `.foo/bar2`, even if they aren't “dotfiles” because the
+    file basenames don't start with a period.
+
+5.  (Optional.) Set `annex.dotfiles` back to false, change directory to
+    `.foo`, then run `git annex add bar3`. The file will be added to the
+    annex, as it is no longer recognized as a dotfile. This shows that
+    git-annex's behavior is inconsistent: the same file is either seen as
+    a dotfile or not, depending on which directory git-annex is run from and
+    what the resulting relative pathnames look like.
+
+### What version of git-annex are you using? On what operating system?
+
+git-annex v8.20200330, on Debian sid, as of 2020-05-08
+
+### Please provide any additional information below.
+
+[[!format sh """
+$ cd /tmp/git-annex-dotfiles
+$ git init
+Initialized empty Git repository in /tmp/git-annex-dotfiles/.git/
+$ git annex init
+init  (scanning for unlocked files...)
+ok
+(recording state in git...)
+$ mkdir .foo
+$ echo a > .foo/bar1
+$ echo b > .foo/bar2
+$ echo c > .foo/bar3
+$ git annex add .foo/bar1   # I expect this to be added to the annex, but no
+add .foo/bar1 (non-large file; adding content to git repository) ok
+(recording state in git...)
+$ git config annex.dotfiles true
+$ git annex add .foo/bar2   # clearly affected by annex.dotfiles
+add .foo/bar2
+ok
+(recording state in git...)
+$ git config annex.dotfiles false
+$ cd .foo
+$ git annex add bar3        # clearly affected by the exact relative pathname
+add bar3
+ok
+(recording state in git...)
+"""]]
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+
+Yes. git-annex has been in use on my end for a couple of years, and it is my
+go-to solution for “want something versioned, but can't store the
+contents themselves (too big, too sensitive, etc.)?”. Furthermore, git-annex
+documentation in general is excellent. But that is also why I'm stumped that
+the manual is so silent on this point.

addurl --preserve-filename and a few related changes
* addurl --preserve-filename: New option, uses server-provided filename
without any sanitization, but with some security checking.
Not yet implemented for remotes other than the web.
* addurl, importfeed: Avoid adding filenames with leading '.', instead
it will be replaced with '_'.
This might be considered a security fix, but a CVE seems unwattanted.
It was possible for addurl to create a dotfile, which could change
behavior of some program. It was also possible for a web server to say
the file name was ".git" or "foo/.git". That would not overrwrite the
.git directory, but would cause addurl to fail; of course git won't
add "foo/.git".
sanitizeFilePath is too opinionated to remain in Utility, so moved it.
The changes to mkSafeFilePath are because it used sanitizeFilePath.
In particular:
isDrive will never succeed, because "c:" gets munged to "c_"
".." gets sanitized now
".git" gets sanitized now
It will never be null, because sanitizeFilePath keeps the length
the same, and splitDirectories never returns a null path.
Also, on the off chance a web server suggests a filename of "",
ignore that, rather than trying to save to such a filename, which would
fail in some way.
diff --git a/Annex/UntrustedFilePath.hs b/Annex/UntrustedFilePath.hs
new file mode 100644
index 000000000..29c02709f
--- /dev/null
+++ b/Annex/UntrustedFilePath.hs
@@ -0,0 +1,56 @@
+{- handling untrusted filepaths
+ -
+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module Annex.UntrustedFilePath where
+
+import Data.Char
+import System.FilePath
+
+{- Given a string that we'd like to use as the basis for FilePath, but that
+ - was provided by a third party and is not to be trusted, returns the closest
+ - sane FilePath.
+ -
+ - All spaces and punctuation and other wacky stuff are replaced
+ - with '_', except for '.'
+ -
+ - "../" becomes ".._", which is safe.
+ - "/foo" becomes "_foo", which is safe.
+ - "c:foo" becomes "c_foo", which is safe even on windows.
+ - 
+ - Leading '.' is also replaced with '_', so ".git/foo" becomes "_git_foo"
+ - and so no dotfiles that might control a program are inadvertently created.
+ -}
+sanitizeFilePath :: String -> FilePath
+sanitizeFilePath = leadingdot . map sanitize
+  where
+	sanitize c
+		| c == '.' = c
+		| isSpace c || isPunctuation c || isSymbol c || isControl c || c == '/' = '_'
+		| otherwise = c
+
+	leadingdot ('.':s) = '_':s
+	leadingdot s = s
+
+escapeSequenceInFilePath :: FilePath -> Bool
+escapeSequenceInFilePath f = '\ESC' `elem` f
+
+{- ../ is a path traversal, no matter where it appears.
+ -
+ - An absolute path is, of course.
+ -}
+pathTraversalInFilePath :: FilePath -> Bool
+pathTraversalInFilePath f
+	| isAbsolute f = True
+	| any (== "..") (splitPath f) = True
+	-- On windows, C:foo with no directory is not considered absolute
+	| hasDrive f = True 
+	| otherwise = False
+
+gitDirectoryInFilePath :: FilePath -> Bool
+gitDirectoryInFilePath = any (== ".git")
+	. map dropTrailingPathSeparator
+	. splitPath 
diff --git a/CHANGELOG b/CHANGELOG
index 4afb03eb6..ad4d9ad3c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,10 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
   * git-lfs repos that encrypt the annexed content but not the git repo
     only need --force passed to initremote, allow enableremote and
     autoenable of such remotes without forcing again.
+  * addurl, importfeed: Avoid adding filenames with leading '.', instead
+    it will be replaced with '_'.
+  * addurl --preserve-filename: New option, uses server-provided filename
+    without any sanitization, but with some security checking.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Command/AddUrl.hs b/Command/AddUrl.hs
index 9097b7f94..73746e8c1 100644
--- a/Command/AddUrl.hs
+++ b/Command/AddUrl.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2011-2017 Joey Hess <id@joeyh.name>
+ - Copyright 2011-2020 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -23,6 +23,7 @@ import Annex.CheckIgnore
 import Annex.Perms
 import Annex.UUID
 import Annex.YoutubeDl
+import Annex.UntrustedFilePath
 import Logs.Web
 import Types.KeySource
 import Types.UrlContents
@@ -52,6 +53,7 @@ data DownloadOptions = DownloadOptions
 	{ relaxedOption :: Bool
 	, rawOption :: Bool
 	, fileOption :: Maybe FilePath
+	, preserveFilenameOption :: Bool
 	}
 
 optParser :: CmdParamsDesc -> Parser AddUrlOptions
@@ -77,7 +79,7 @@ optParser desc = AddUrlOptions
 		)
 
 parseDownloadOptions :: Bool -> Parser DownloadOptions
-parseDownloadOptions withfileoption = DownloadOptions
+parseDownloadOptions withfileoptions = DownloadOptions
 	<$> switch
 		( long "relaxed"
 		<> help "skip size check"
@@ -86,12 +88,18 @@ parseDownloadOptions withfileoption = DownloadOptions
 		( long "raw"
 		<> help "disable special handling for torrents, youtube-dl, etc"
 		)
-	<*> if withfileoption
+	<*> (if withfileoptions
 		then optional (strOption
 			( long "file" <> metavar paramFile
 			<> help "specify what file the url is added to"
 			))
-		else pure Nothing
+		else pure Nothing)
+	<*> (if withfileoptions
+		then switch
+			( long "preserve-filename"
+			<> help "use filename provided by server as-is"
+			)
+		else pure False)
 
 seek :: AddUrlOptions -> CommandSeek
 seek o = startConcurrency commandStages $ do
@@ -207,16 +215,35 @@ startWeb addunlockedmatcher o urlstring = go $ fromMaybe bad $ parseURI urlstrin
 		file <- adjustFile o <$> case fileOption (downloadOptions o) of
 			Just f -> pure f
 			Nothing -> case Url.urlSuggestedFile urlinfo of
-				Nothing -> pure $ url2file url (pathdepthOption o) pathmax
-				Just sf -> do
-					let f = truncateFilePath pathmax $
-						sanitizeFilePath sf
-					ifM (liftIO $ doesFileExist f <||> doesDirectoryExist f)
-						( pure $ url2file url (pathdepthOption o) pathmax
-						, pure f
-						)
+				Just sf | not (null sf) -> if preserveFilenameOption (downloadOptions o)
+					then do
+						checkPreserveFileNameSecurity sf
+						return sf
+					else do
+						let f = truncateFilePath pathmax $
+							sanitizeFilePath sf
+						ifM (liftIO $ doesFileExist f <||> doesDirectoryExist f)
+							( pure $ url2file url (pathdepthOption o) pathmax
+							, pure f
+							)
+				_ -> pure $ url2file url (pathdepthOption o) pathmax
 		performWeb addunlockedmatcher o urlstring file urlinfo
 
+-- sanitizeFilePath avoids all these security problems
+-- (and probably others, but at least this catches the most egrarious ones).
+checkPreserveFileNameSecurity :: FilePath -> Annex ()
+checkPreserveFileNameSecurity f = do
+	checksecurity escapeSequenceInFilePath False "escape sequence"
+	checksecurity pathTraversalInFilePath True "path traversal"
+	checksecurity gitDirectoryInFilePath True "contains a .git directory"
+  where
+	checksecurity p canshow d = when (p f) $
+		giveup $ concat
+			[ "--preserve-filename was used, but the filename "
+			, if canshow then "(" ++ f ++ ") " else ""
+			, "has a security problem (" ++ d ++ "), not adding."
+			]
+
 performWeb :: AddUnlockedMatcher -> AddUrlOptions -> URLString -> FilePath -> Url.UrlInfo -> CommandPerform
 performWeb addunlockedmatcher o url file urlinfo = ifAnnexed (toRawFilePath file) addurl geturl
   where
diff --git a/Command/ImportFeed.hs b/Command/ImportFeed.hs
index 6b670668c..be03ccb79 100644
--- a/Command/ImportFeed.hs
+++ b/Command/ImportFeed.hs
@@ -40,6 +40,7 @@ import Logs.MetaData
 import Annex.MetaData
 import Annex.FileMatcher
 import Command.AddUrl (addWorkTree)
+import Annex.UntrustedFilePath
 
 cmd :: Command
 cmd = notBareRepo $
diff --git a/Types/UrlContents.hs b/Types/UrlContents.hs
index c68efd00a..7cbfe37f8 100644
--- a/Types/UrlContents.hs
+++ b/Types/UrlContents.hs
@@ -13,7 +13,7 @@ module Types.UrlContents (
 ) where
 
 import Utility.Url
-import Utility.Path

(Diff truncated)
note
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_2_f787daed9b02af18b81f033cc2f84d0b._comment b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_2_f787daed9b02af18b81f033cc2f84d0b._comment
new file mode 100644
index 000000000..0e7b2f2d1
--- /dev/null
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_2_f787daed9b02af18b81f033cc2f84d0b._comment
@@ -0,0 +1,26 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2020-05-08T18:19:20Z"
+ content="""
+`git-annex import` does not do any sanitization, and that could be
+considered inconsistent, particularly when importing from a remote like S3.
+
+A difference with that is, it creates a remote tracking branch for the
+imported files. (That happens to avoid "../" path traversal because git
+generally avoids it.) Maybe the real difference is, import from a special
+remote is completely analagous to fetching from a git remote. So it feels
+different to me than adding an url does. 
+
+If I sync with a S3 bucket and it turns out it imported a escape sequence
+file, well I could have looked at the bucket first, or imported and
+reviewed the branch before merging it. And if I was syncing with a git
+remote the same thing could happen. So it feels like I should have no
+expectation git-annex would protect me. Whereis, if I add an url and the
+web server uses an obscure-ish http header to surprise me with a similar
+malicious filename, I had no way before hand to know that would happen, and
+so it does feel like git-annex should protect me.
+
+(Although if git did prevent that, git-annex should too, and I'd be
+fine with git preventing that.)
+"""]]

comment
diff --git a/doc/bugs/Share_with_a_friend_fails/comment_1_d3ba5f786c45e677ea9a7b4a7b36e1a9._comment b/doc/bugs/Share_with_a_friend_fails/comment_1_d3ba5f786c45e677ea9a7b4a7b36e1a9._comment
new file mode 100644
index 000000000..16378dc40
--- /dev/null
+++ b/doc/bugs/Share_with_a_friend_fails/comment_1_d3ba5f786c45e677ea9a7b4a7b36e1a9._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-08T17:18:08Z"
+ content="""
+So it's trying to run "su -c". Does your OSX have the "osascript"
+command available? It's supposed to use that when available, which is the
+right way to run a command as root on OSX.
+"""]]

comment
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_1_6450f220a0d4252ceafdd82f0cc24486._comment b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_1_6450f220a0d4252ceafdd82f0cc24486._comment
new file mode 100644
index 000000000..29b8b8265
--- /dev/null
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_/comment_1_6450f220a0d4252ceafdd82f0cc24486._comment
@@ -0,0 +1,42 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-08T16:50:14Z"
+ content="""
+This is due to the filename being passed through sanitizeFilePath.
+
+There are security concerns here. If the filename contains "../"
+it absolutely has to be modified, or the command would have to fail and
+refuse the import it.
+
+If the filename contains an ANSI escape sequence, it could potentially
+lead to a security hole. Or if the filename starts with "-" it could be
+somewhere between a possible security hole and just very annoying to work
+with. As could a filename that contains a newline, which will
+break large quantities of shell pipelines. While generally git repos can
+have these problems with files in them too, the exposure seems larger when
+talking to some random web server than when pulling from a repo.
+
+Also, cross filesystem compatibility is a concern. It used to allow "|" in
+the filename, but a bug pointed out that cannot be used on fat filesystems.
+And "\\" means different things on linux and windows, so probably best to avoid
+filenames containing it on linux too.
+
+Finally, it's somewhat opinionated, since it replaces spaces with
+underscores. That's certainly the least defensible thing.
+
+(git-annex may also truncate the filename if it's longer than what the
+filesystem supports.)
+
+So, it's clearly wrong that it should be taken as-is without obfuscation,
+IMHO. Maybe there's a way to improve it to meet some use case though.
+
+I could see having a config that avoids sanitizing the filename, but
+makes addurl fail if the filename looks like a security problem. 
+
+Though that has the downside that git-annex would then need to
+comprehensively track, going forward, all the ways that people find to make
+filenames be a security problem; the current method, by being strict in
+what it lets through, probably limits expoits to ones involving a) unicode
+or b) the user's wetware.
+"""]]

diff --git a/doc/bugs/Share_with_a_friend_fails.mdwn b/doc/bugs/Share_with_a_friend_fails.mdwn
index 06cb0d6f8..010fa03b8 100644
--- a/doc/bugs/Share_with_a_friend_fails.mdwn
+++ b/doc/bugs/Share_with_a_friend_fails.mdwn
@@ -49,4 +49,4 @@ git-annex: enable-tor: 1 failed
 
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
 
-
+git-annex is working well syncing with my rsync.net account

diff --git a/doc/bugs/Share_with_a_friend_fails.mdwn b/doc/bugs/Share_with_a_friend_fails.mdwn
index 5d18950bd..06cb0d6f8 100644
--- a/doc/bugs/Share_with_a_friend_fails.mdwn
+++ b/doc/bugs/Share_with_a_friend_fails.mdwn
@@ -3,7 +3,9 @@ Fails with below error
 
 ### What steps will reproduce the problem?
 Click add another repository
+
 Click Let's get start
+
 Receive Error
 
 ### What version of git-annex are you using? On what operating system?

diff --git a/doc/bugs/Share_with_a_friend_fails.mdwn b/doc/bugs/Share_with_a_friend_fails.mdwn
new file mode 100644
index 000000000..5d18950bd
--- /dev/null
+++ b/doc/bugs/Share_with_a_friend_fails.mdwn
@@ -0,0 +1,50 @@
+### Please describe the problem.
+Fails with below error
+
+### What steps will reproduce the problem?
+Click add another repository
+Click Let's get start
+Receive Error
+
+### What version of git-annex are you using? On what operating system?
+git-annex version 8.20200501
+MacOS 10.15.4 (19E287)
+
+### Please provide any additional information below.
+
+[[!format sh """
+# If you can, paste a complete transcript of the problem occurring here.
+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log
+[2020-05-07 15:01:42.693876] main: starting assistant version 8.20200501
+(scanning...) [2020-05-07 15:01:42.754501] Watcher: Performing startup scan
+(started...) 
+07/May/2020:15:01:56 -0700 [Error#yesod-core] Failed to enable tor
+
+enable-tor 
+  You will be prompted for root's password
+su: illegal option -- c
+usage: su [-] [-flm] [login [args]]
+
+git-annex: Failed to run as root: /usr/local/Cellar/git-annex/8.20200501/bin/git-annex enable-tor 501
+failed
+git-annex: enable-tor: 1 failed
+ @(yesod-core-1.6.18-Chd8Br2Wdd9GRfQbrxaPhy:Yesod.Core.Class.Yesod src/Yesod/Core/Class/Yesod.hs:688:5)
+07/May/2020:15:04:58 -0700 [Error#yesod-core] Failed to enable tor
+
+enable-tor 
+  You will be prompted for root's password
+su: illegal option -- c
+usage: su [-] [-flm] [login [args]]
+
+git-annex: Failed to run as root: /usr/local/Cellar/git-annex/8.20200501/bin/git-annex enable-tor 501
+failed
+git-annex: enable-tor: 1 failed
+ @(yesod-core-1.6.18-Chd8Br2Wdd9GRfQbrxaPhy:Yesod.Core.Class.Yesod src/Yesod/Core/Class/Yesod.hs:688:5)
+
+
+# End of transcript or log.
+"""]]
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+
+

original complaint about filenames obfuscated by addurl
diff --git a/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn
new file mode 100644
index 000000000..390160b92
--- /dev/null
+++ b/doc/bugs/addurl__58___content-disposition_field_should_be_taken_as_is_without_obfuscation_.mdwn
@@ -0,0 +1,47 @@
+### Please describe the problem.
+
+Original complaints could be found mentioned in the comments of the [importfeed page](https://git-annex.branchable.com/git-annex-importfeed/): when using `addurl`, and even when the server provides Content-Disposition field with the filename, git-annex seems (BTW -- no Content-Disposition was mentioned in the --debug output) to take that filename value and obfuscates it (replaces '-' with '_' etc) to what supposed to be the original filename.
+
+
+[[!format sh """
+$> mkdir /tmp/testrepo; cd /tmp/testrepo; git init; git annex init; 
+mkdir: cannot create directory ‘/tmp/testrepo’: File exists
+E: could not determine git repository root
+Initialized empty Git repository in /tmp/testrepo/.git/
+init  ok
+(recording state in git...)
+
+$> git annex addurl --fast  https://girder.dandiarchive.org/api/v1/item/5e9f9588b5c9745bad9f58ff/download      
+addurl https://girder.dandiarchive.org/api/v1/item/5e9f9588b5c9745bad9f58ff/download (to sub_mouse_AAYYT_ses_20180420_sample_2_slice_20180420_slice_2_cell_20180420_sample_2.nwb) ok
+(recording state in git...)
+
+$> ls -l
+total 4
+lrwxrwxrwx 1 yoh yoh 184 May  7 17:02 sub_mouse_AAYYT_ses_20180420_sample_2_slice_20180420_slice_2_cell_20180420_sample_2.nwb -> .git/annex/objects/Gj/9z/URL-s9335000--https&c%%girder.dandiarchive.org-48163bc503cb7181516be86ef215f923/URL-s9335000--https&c%%girder.dandiarchive.org-48163bc503cb7181516be86ef215f923
+"""]]]
+
+whenever original content-disposition was having "-" in the filename, which are perfectly safe the filename AFAIK:
+
+[[!format sh """
+$> wget -S https://girder.dandiarchive.org/api/v1/item/5e9f9588b5c9745bad9f58ff/download                
+... bunch of forwards to the final one with the content disposition field
+Resolving dandiarchive.s3.amazonaws.com (dandiarchive.s3.amazonaws.com)... 52.219.101.51
+Connecting to dandiarchive.s3.amazonaws.com (dandiarchive.s3.amazonaws.com)|52.219.101.51|:443... connected.
+HTTP request sent, awaiting response... 
+  HTTP/1.1 200 OK
+  x-amz-id-2: VgJE1jV5XUkBQXZDWgR5WEDfmHJp4Fj6fGo6z2tYkLfyTsxDWC+m92B2qOSVppCuiRFu2QpNV5M=
+  x-amz-request-id: 1221CAC30E3931CF
+  Date: Thu, 07 May 2020 21:02:52 GMT
+  Last-Modified: Wed, 22 Apr 2020 00:54:32 GMT
+  ETag: "acf3b4f5951435245a0efcd4a518e77d"
+  Content-Disposition: attachment; filename="sub-mouse-AAYYT_ses-20180420-sample-2_slice-20180420-slice-2_cell-20180420-sample-2.nwb"
+...
+
+$> git annex version
+git-annex version: 7.20190708+git9-gfa3524b95-1~ndall+1
+
+"""]]
+
+
+[[!meta author=yoh]]
+[[!tag projects/dandi]]

S3: Support signature=v4
To use S3 Signature Version 4. Some S3 services seem to require v4, while
others may only support v2, which remains the default.
I'm also not sure if v4 works correctly in all cases, there is this
upstream bug report: https://github.com/aristidb/aws/issues/262
I've only tested it against the default S3 endpoint.
diff --git a/CHANGELOG b/CHANGELOG
index dc40de0f3..9dcefbbf0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,9 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
   * sync: Avoid an ugly error message when nothing has been committed to
     master yet and there is a synced master branch to merge from.
   * upgrade: When upgrade fails due to an exception, display it.
+  * S3: Support signature=v4, to use S3 Signature Version 4.
+    Some S3 services seem to require v4, while others may only
+    support v2, which remains the default.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Remote/S3.hs b/Remote/S3.hs
index cb345d1f8..e3ea492f2 100644
--- a/Remote/S3.hs
+++ b/Remote/S3.hs
@@ -99,6 +99,8 @@ remote = specialRemoteType $ RemoteType
 				(FieldDesc "port to connect to")
 			, optionalStringParser requeststyleField
 				(FieldDesc "for path-style requests, set to \"path\"")
+			, signatureVersionParser signatureField
+				(FieldDesc "S3 signature version")
 			, optionalStringParser mungekeysField HiddenField
 			, optionalStringParser AWS.s3credsField HiddenField
 			]
@@ -148,6 +150,22 @@ protocolField = Accepted "protocol"
 requeststyleField :: RemoteConfigField
 requeststyleField = Accepted "requeststyle"
 
+signatureField :: RemoteConfigField
+signatureField = Accepted "signature"
+
+newtype SignatureVersion = SignatureVersion Int
+
+signatureVersionParser :: RemoteConfigField -> FieldDesc -> RemoteConfigFieldParser
+signatureVersionParser f fd =
+	genParser go f defver fd
+		(Just (ValueDesc "v2 or v4"))
+  where
+	go "v2" = Just (SignatureVersion 2)
+	go "v4" = Just (SignatureVersion 4)
+	go _ = Nothing
+
+	defver = SignatureVersion 2
+
 portField :: RemoteConfigField
 portField = Accepted "port"
 
@@ -877,7 +895,10 @@ s3Configuration c = cfg
 		Nothing
 			| port == 443 -> AWS.HTTPS
 			| otherwise -> AWS.HTTP
-	cfg = S3.s3 proto endpoint False
+	cfg = case getRemoteConfigValue signatureField c of
+		Just (SignatureVersion 4) -> 
+			S3.s3v4 proto endpoint False S3.SignWithEffort
+		_ -> S3.s3 proto endpoint False
 
 data S3Info = S3Info
 	{ bucket :: S3.Bucket
diff --git a/doc/bugs/S3_special_remote_support_for_DigitalOcean_Spaces/comment_2_3bbdf23c8a4a480f4f6b8e8a2f8ddecd._comment b/doc/bugs/S3_special_remote_support_for_DigitalOcean_Spaces/comment_2_3bbdf23c8a4a480f4f6b8e8a2f8ddecd._comment
new file mode 100644
index 000000000..14bce58c3
--- /dev/null
+++ b/doc/bugs/S3_special_remote_support_for_DigitalOcean_Spaces/comment_2_3bbdf23c8a4a480f4f6b8e8a2f8ddecd._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2020-05-07T16:46:14Z"
+ content="""
+I have added to git-annex a way to use v4 authentication signatures.
+
+You will need a daily build, or the next release of git-annex.
+
+Give it a try by adding signature=v4 to your initremote
+or enableremote, and please let me know if it works or how it fails with
+that.
+"""]]
diff --git a/doc/forum/backblaze_s3/comment_1_854390b9a781da82ecb85ad85eecad04._comment b/doc/forum/backblaze_s3/comment_1_854390b9a781da82ecb85ad85eecad04._comment
new file mode 100644
index 000000000..357fdc559
--- /dev/null
+++ b/doc/forum/backblaze_s3/comment_1_854390b9a781da82ecb85ad85eecad04._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-07T16:23:26Z"
+ content="""
+It may be that they are only supporting a newer version of the S3
+protocol that does authorization differently. The S3 library
+git-annex uses defaults to V2 not V4.
+
+I thought that library didn't properly support V4, but it seems it does,
+although I don't know if it works in all cases. So, I've added an
+initremote option for S3, signature=v4 .. give it a try.
+"""]]
diff --git a/doc/special_remotes/S3.mdwn b/doc/special_remotes/S3.mdwn
index 6221dd955..c8d6a975f 100644
--- a/doc/special_remotes/S3.mdwn
+++ b/doc/special_remotes/S3.mdwn
@@ -77,6 +77,10 @@ the S3 remote.
   If you get an error about a host name not existing, it's a good
   indication that you need to use this.
 
+* `signature` - This controls the S3 signature version to use.
+  "v2" is currently the default, "v4" is needed to use some S3 services.
+  If you get some kind of authentication error, try "v4".
+
 * `bucket` - S3 requires that buckets have a globally unique name, 
   so by default, a bucket name is chosen based on the remote name
   and UUID. This can be specified to pick a bucket name.
diff --git a/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment b/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment
new file mode 100644
index 000000000..71303b530
--- /dev/null
+++ b/doc/special_remotes/S3/comment_34_cf57e8dbd9fdc7c487565b61808b6bb2._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""V4"""
+ date="2020-05-07T16:49:05Z"
+ content="""
+@bec.watson, I've now added a way to use V4 authentication, the authentication=v4
+option. 
+
+Please file a bug report if it still doesn't work.
+"""]]

upgrade: When upgrade fails due to an exception, display it.
37b42e72e7485d56f2b4bfd63eeb43d8ebd8ceb5 made it catch exceptions but
thought they were unlikely to be useful to display, which may be right when
a git command fails, but not in the case yoh found.
diff --git a/CHANGELOG b/CHANGELOG
index f7ac9f1a0..dc40de0f3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,7 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
   * repair: Improve fetching from a remote with an url in host:path format.
   * sync: Avoid an ugly error message when nothing has been committed to
     master yet and there is a synced master branch to merge from.
+  * upgrade: When upgrade fails due to an exception, display it.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Upgrade/V5.hs b/Upgrade/V5.hs
index 0e0368d11..7ce66003d 100644
--- a/Upgrade/V5.hs
+++ b/Upgrade/V5.hs
@@ -36,7 +36,7 @@ import Annex.AdjustedBranch
 import qualified Data.ByteString as S
 
 upgrade :: Bool -> Annex Bool
-upgrade automatic = flip catchNonAsync (const $ return False) $ do
+upgrade automatic = flip catchNonAsync onexception $ do
 	unless automatic $
 		showAction "v5 to v6"
 	ifM isDirect
@@ -55,6 +55,10 @@ upgrade automatic = flip catchNonAsync (const $ return False) $ do
 	unlessM isDirect $
 		createInodeSentinalFile True
 	return True
+  where
+	onexception e = do
+		warning $ "caught exception: " ++ show e
+		return False
 
 -- git before 2.22 would OOM running git status on a large file.
 --
diff --git a/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn b/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn
index 33815b7a8..e9b059708 100644
--- a/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn
+++ b/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn
@@ -150,4 +150,4 @@ So it seems git-annex should revert back to reporting errors from underlying `gi
 [[!meta author=yoh]]
 [[!tag projects/datalad]]
 
-
+> [[fixed|done]], thanks for tracking it back to the root cause. --[[Joey]] 

respond and close
diff --git a/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead.mdwn b/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead.mdwn
index 9ca1e09e4..34fb1c4f3 100644
--- a/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead.mdwn
+++ b/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead.mdwn
@@ -45,3 +45,5 @@ Additionally the key will still remain in the `git-annex` branch, I'm not sure a
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
 
 I'm using git annex to manage all my personal data, thanks for making such an amazing piece of software :)
+
+> [[notabug|done]] --[[Joey]] 
diff --git a/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead/comment_4_39e375d942289b07116600f1a22da5be._comment b/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead/comment_4_39e375d942289b07116600f1a22da5be._comment
new file mode 100644
index 000000000..6185eef97
--- /dev/null
+++ b/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead/comment_4_39e375d942289b07116600f1a22da5be._comment
@@ -0,0 +1,25 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2020-05-07T15:56:38Z"
+ content="""
+`git annex get` will only complain about files that are still in the
+current branch. If you want to use `--all` though, you will have to mark
+such files as dead. git-annex otherwise has no way to differentiate between
+the last copy of a file being lost inaverdently and intentionally removed.
+
+Auto-deading files would hide problems.
+
+> even marking it as dead is still tracking the deadness of the file
+
+You can use git-annex forget to prune that information from the git-annex
+branch, but it's completely reasonable for a git repository to retain
+history by default.
+
+> Leaving aside what the status is called, how about detecting it
+> automatically on `dropunused`
+
+Unused files are only unused in the head of branches, not in all the
+history of the git repository. Again, git is all about preserving the
+history of files.
+"""]]

initial report on silent fail to upgrade
diff --git a/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn b/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn
new file mode 100644
index 000000000..33815b7a8
--- /dev/null
+++ b/doc/bugs/upgrade___40__from_v5__41___fails_without_stating_any_reason__47__hints.mdwn
@@ -0,0 +1,153 @@
+### Please describe the problem.
+
+I got into a repository I have not used for a while, and then `datalad` commands failed because annex failed to upgrade it from v5.  No details/reason is given at any level making it impossible to figure out for a user what to do/try next:
+
+<details>
+<summary>very original datalad invocation (click to expand)</summary> 
+
+[[!format sh """
+(git-annex)lena:~pymvpa/papers[master]bib
+$> datalad run -m "Regenerate haxbylab_hl.bib" --input haxbylab.bib --output haxbylab_hl.bib --explicit 'make {outputs}'
+[INFO   ] Making sure inputs are available (this may take some time) 
+CommandError: command '['git', '-c', 'annex.merge-annex-branches=false', 'annex', 'find', '-c', 'annex.dotfiles=true', '-c', 'remote.origin.annex-ssh-options=-o ControlMaster=auto -S /home/yoh/.cache/datalad/sockets/git.pymvpa.org -o ControlMaster=auto -S /home/yoh/.cache/datalad/sockets/1d961cfa', '--json', '--json-error-messages', '--not', '--in', '.', '--', 'bib/haxbylab.bib']' failed with exitcode 1
+Failed to run ['git', '-c', 'annex.merge-annex-branches=false', 'annex', 'find', '-c', 'annex.dotfiles=true', '-c', 'remote.origin.annex-ssh-options=-o ControlMaster=auto -S /home/yoh/.cache/datalad/sockets/git.pymvpa.org -o ControlMaster=auto -S /home/yoh/.cache/datalad/sockets/1d961cfa', '--json', '--json-error-messages', '--not', '--in', '.', '--', 'bib/haxbylab.bib'] under '/home/yoh/proj/pymvpa/papers'. Exit code=1. out= err=git-annex: Repository /home/yoh/proj/pymvpa/papers is at unsupported version 5. Automatic upgrade failed!
+
+git-annex: Repository /home/yoh/proj/pymvpa/papers is at unsupported version 5. Automatic upgrade failed!
+"""]]
+
+</details>
+
+[[!format sh """
+$> git annex version
+git-annex version: 8.20200309+git133-gc29943f40-1~ndall+1
+
+$> git annex info
+git-annex: Repository /home/yoh/proj/pymvpa/papers is at unsupported version 5. Automatic upgrade failed!
+
+
+$> git annex upgrade
+upgrade (v5 to v6...) failed
+git-annex: upgrade: 1 failed
+
+
+$> git annex upgrade --debug
+upgrade (v5 to v6...) [2020-05-07 10:52:03.727276447] read: git ["--version"]
+[2020-05-07 10:52:03.730015743] process done ExitSuccess
+[2020-05-07 10:52:03.730119216] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","show-ref","--head"]
+[2020-05-07 10:52:03.733213698] process done ExitSuccess
+[2020-05-07 10:52:03.733691083] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","ls-tree","--full-tree","-z","-r","--","HEAD"]
+[2020-05-07 10:52:03.736803336] chat: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","cat-file","--batch"]
+[2020-05-07 10:52:03.737004108] chat: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","cat-file","--batch-check=%(objectname) %(objecttype) %(objectsize)"]
+[2020-05-07 10:52:03.954238715] process done ExitSuccess
+[2020-05-07 10:52:03.954308318] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","status","--porcelain"]
+[2020-05-07 10:52:04.017909723] process done ExitSuccess
+[2020-05-07 10:52:04.018217705] call: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","config","filter.annex.smudge","git-annex smudge -- %f"]
+[2020-05-07 10:52:04.022805323] process done ExitSuccess
+[2020-05-07 10:52:04.022870176] read: git ["config","--null","--list"]
+[2020-05-07 10:52:04.025862758] process done ExitSuccess
+[2020-05-07 10:52:04.025898818] call: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","config","filter.annex.clean","git-annex smudge --clean -- %f"]
+[2020-05-07 10:52:04.028657032] process done ExitSuccess
+[2020-05-07 10:52:04.028691215] read: git ["config","--null","--list"]
+[2020-05-07 10:52:04.031420328] process done ExitSuccess
+failed
+[2020-05-07 10:52:04.055445542] process done ExitSuccess
+[2020-05-07 10:52:04.058899774] process done ExitSuccess
+git-annex: upgrade: 1 failed
+
+"""]]
+
+Downgrading git-annex to 7.20190819+git2-g908476a9b-1~ndall+1 helped to reveal the issue:
+
+[[!format sh """
+$> git annex upgrade --debug                                                     
+upgrade (v5 to v6...) [2020-05-07 10:56:49.99032766] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","show-ref","--head"]
+[2020-05-07 10:56:50.00402489] process done ExitSuccess
+(scanning for unlocked files...)
+[2020-05-07 10:56:50.004777461] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","ls-tree","--full-tree","-z","-r","--","HEAD"]
+[2020-05-07 10:56:50.019113817] chat: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","cat-file","--batch"]
+[2020-05-07 10:56:50.020051726] chat: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","cat-file","--batch-check=%(objectname) %(objecttype) %(objectsize)"]
+[2020-05-07 10:56:50.414585722] process done ExitSuccess
+[2020-05-07 10:56:50.414672616] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","status","--porcelain"]
+[2020-05-07 10:56:50.532708468] process done ExitSuccess
+[2020-05-07 10:56:50.532790172] call: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","config","filter.annex.smudge","git-annex smudge -- %f"]
+[2020-05-07 10:56:50.536471232] process done ExitSuccess
+[2020-05-07 10:56:50.536530991] read: git ["config","--null","--list"]
+[2020-05-07 10:56:50.540818414] process done ExitSuccess
+[2020-05-07 10:56:50.540897171] call: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","config","filter.annex.clean","git-annex smudge --clean -- %f"]
+[2020-05-07 10:56:50.544562826] process done ExitSuccess
+[2020-05-07 10:56:50.544626978] read: git ["config","--null","--list"]
+[2020-05-07 10:56:50.552390589] process done ExitSuccess
+
+git-annex: ../.git/info/attributes: openFile: permission denied (Permission denied)
+failed
+[2020-05-07 10:56:50.57632181] process done ExitSuccess
+[2020-05-07 10:56:50.578345312] process done ExitSuccess
+git-annex: upgrade: 1 failed
+
+$> git annex version
+git-annex version: 7.20190819+git2-g908476a9b-1~ndall+1
+build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
+dependency versions: aws-0.20 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.3 feed-1.0.0.0 ghc-8.4.4 http-client-0.5.13.1 persistent-sqlite-2.8.2 torrent-10000.1.1 uuid-1.3.13 yesod-1.6.0
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs hook external
+operating system: linux x86_64
+supported repository versions: 5 7
+upgrade supported from repository versions: 0 1 2 3 4 5 6
+local repository version: 5
+
+$> git annex info           
+repository mode: indirect
+trusted repositories: 0
+semitrusted repositories: 5
+	00000000-0000-0000-0000-000000000001 -- web
+ 	00000000-0000-0000-0000-000000000002 -- bittorrent
+ 	4435399f-0e03-432c-9ab2-cab8df04fc9b -- mih@meiner:~/psycho/papers/belka
+ 	bcefa304-7d94-11e3-bb19-532dbfa67366 -- origin
+ 	c44ff4fd-1cfb-46f9-b5d1-c471208c4947 -- yoh@novo:~/proj/pymvpa/papers [here]
+untrusted repositories: 0
+transfers in progress: none
+available local disk space: 504.74 gigabytes (+1 megabyte reserved)
+temporary object directory size: 10.72 megabytes (clean up with git-annex unused)
+local annex keys: 242
+local annex size: 50.57 megabytes
+annexed files in working tree: 229
+size of annexed files in working tree: 377.47 megabytes
+bloom filter size: 32 mebibytes (0% full)
+backend usage: 
+	SHA256E: 229
+
+$> git annex upgrade
+upgrade (v5 to v6...) (scanning for unlocked files...)
+
+git-annex: ../.git/info/attributes: openFile: permission denied (Permission denied)
+failed
+git-annex: upgrade: 1 failed
+
+"""]]
+
+note that `info` works out without failing to upgrade with that older version.
+
+and indeed somehow I have:
+
+[[!format sh """
+$> ls -ld ../.git/info/attributes           
+-rw-r--r-- 1 root yoh 39 Jun  5  2009 ../.git/info/attributes
+
+$> find .git -uid 0
+.git/hooks/pre-commit.disabled
+.git/info/attributes
+"""]]
+
+fixing ownership and rerunning upgrade worked (older version was remained used):
+[[!format sh """
+$> git annex upgrade
+upgrade (v5 to v6...) (scanning for unlocked files...)
+(v6 to v7...) ok
+"""]]
+
+So it seems git-annex should revert back to reporting errors from underlying `git` invocations to make it possible to debug such cases
+
+[[!meta author=yoh]]
+[[!tag projects/datalad]]
+
+

Added a comment: Is `dead` really the solution here?
diff --git a/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead/comment_3_9cc112dc5814b45966f48ecdb6376180._comment b/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead/comment_3_9cc112dc5814b45966f48ecdb6376180._comment
new file mode 100644
index 000000000..b4c35097a
--- /dev/null
+++ b/doc/bugs/Deleting_last_copy_of_files_doesn__39__t_mark_them_dead/comment_3_9cc112dc5814b45966f48ecdb6376180._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="glasserc"
+ avatar="http://cdn.libravatar.org/avatar/8e865c04033751520601e9c15e58ddc4"
+ subject="Is `dead` really the solution here?"
+ date="2020-05-06T20:29:03Z"
+ content="""
+I encountered this behavior as well on an annex where I had decided to move a file into a different, unrelated repository. I used `dropunused` to get rid of the contents. Now I have a repository for which `git annex get` constantly complains that a file is not known to be in any repository.
+
+As a naive user, I wouldn't have considered \"dead\" to be the description for this file. It isn't lost in any way, just untracked in the context of this repository. It's a bit surprising that once a file is ever tracked, it can never be untracked by any means -- even marking it as dead is still tracking the deadness of the file.
+
+I guess from a theoretical point of view that some branch or some repo somewhere might still refer to the file in some way and its absence might therefore have consequences later on. From a practical point of view, once the commit removing the last link to the file is on master on all known repositories, it seems like we can consider this file \"deleted\" in a way that is distinct from \"dead\".
+
+Leaving aside what the status is called, how about detecting it automatically on `dropunused`? This is a bit different from detecting it on `drop` because we have already concluded that the file is \"gone\" in some way.
+
+"""]]

diff --git a/doc/forum/backblaze_s3.mdwn b/doc/forum/backblaze_s3.mdwn
new file mode 100644
index 000000000..27f3a0cff
--- /dev/null
+++ b/doc/forum/backblaze_s3.mdwn
@@ -0,0 +1,13 @@
+Backblaze announced that they now have S3 storage for buckets created after May 4th.
+
+My current attempt to use it as an S3 remote has me with the following:
+export AWS_ACCESS_KEY_ID=keyID
+export AWS_SECRET_ACCESS_KEY=applicationID
+git-annex initremote backblaze type=S3 host=s3.us-west-000.backblazeb2.com (the full s3 endpoint) embedcreds=yes encryption=hybrid keyid=CA3D8351 bucket=<my bucket name> protocol=https
+
+and the output:
+
+initremote backblaze (encryption setup) (to gpg keys: 41AAE7DCCA3D8351) (checking bucket...) (creating bucket in US...)
+git-annex: S3Error {s3StatusCode = Status {statusCode = 400, statusMessage = ""}, s3ErrorCode = "AuthorizationHeaderMalformed", s3ErrorMessage = "Authorization header does not contain a Credential", s3ErrorResource = Nothing, s3ErrorHostId = Nothing, s3ErrorAccessKeyId = Nothing, s3ErrorStringToSign = Nothing, s3ErrorBucket = Nothing, s3ErrorEndpointRaw = Nothing, s3ErrorEndpoint = Nothing}
+failed
+git-annex: initremote: 1 failed

sync: Avoid an ugly error message when nothing has been committed to master yet and there is a synced master branch to merge from
Now the warning gets displayed, which is better than an arcane git error.
The warning is still kind of ugly, especially when the pull later in the
sync will clear up what it warns about. But, this is an unusual situation
not likely to happen, and if there is no remote to pull from, the warning
message is needed or the sync will seem to succeed despite not merging the
synced master branch.
Would still be better if it could merge the synced master branch in this
situation, making an empty commit to master to do it seems wrong, and
otherwise it would need a whole separate code path, and would bypass using
git merge in favor of say, setting master to the syned branch. Which would
bypass git configs like arguably merge.ff and certianly
merge.verifySignatures. So don't want to do that.
diff --git a/CHANGELOG b/CHANGELOG
index 948b54d0e..f7ac9f1a0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,8 @@ git-annex (8.20200502) UNRELEASED; urgency=medium
     is located in a directory that does not currently exist, to avoid
     silently skipping such a remote.
   * repair: Improve fetching from a remote with an url in host:path format.
+  * sync: Avoid an ugly error message when nothing has been committed to
+    master yet and there is a synced master branch to merge from.
 
  -- Joey Hess <id@joeyh.name>  Mon, 04 May 2020 12:46:11 -0400
 
diff --git a/Command/Sync.hs b/Command/Sync.hs
index ac19f6ab9..837b7422a 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -346,36 +346,41 @@ mergeLocal mergeconfig o currbranch = stopUnless (notOnlyAnnex o) $
 	mergeLocal' mergeconfig o currbranch
 
 mergeLocal' :: [Git.Merge.MergeConfig] -> SyncOptions -> CurrBranch -> CommandStart
-mergeLocal' mergeconfig o currbranch@(Just _, _) =
-	needMerge currbranch >>= \case
+mergeLocal' mergeconfig o currbranch@(Just branch, _) =
+	needMerge currbranch branch >>= \case
 		Nothing -> stop
 		Just syncbranch ->
 			starting "merge" (ActionItemOther (Just $ Git.Ref.describe syncbranch)) $
 				next $ merge currbranch mergeconfig o Git.Branch.ManualCommit syncbranch
-mergeLocal' _ _ (Nothing, madj) = do
-	b <- inRepo Git.Branch.currentUnsafe
-	needMerge (b, madj) >>= \case
+mergeLocal' _ _ currbranch@(Nothing, _) = inRepo Git.Branch.currentUnsafe >>= \case
+	Just branch -> needMerge currbranch branch >>= \case
 		Nothing -> stop
 		Just syncbranch ->
 			starting "merge" (ActionItemOther (Just $ Git.Ref.describe syncbranch)) $ do
-				warning $ "There are no commits yet in the currently checked out branch, so cannot merge any remote changes into it."
+				warning $ "There are no commits yet to branch " ++ Git.fromRef branch ++ ", so cannot merge " ++ Git.fromRef syncbranch ++ " into it."
 				next $ return False
+	Nothing -> stop
 
 -- Returns the branch that should be merged, if any.
-needMerge :: CurrBranch -> Annex (Maybe Git.Branch)
-needMerge (Nothing, _) = return Nothing
-needMerge (Just branch, madj) = ifM (allM id checks)
+needMerge :: CurrBranch -> Git.Branch -> Annex (Maybe Git.Branch)
+needMerge currbranch headbranch = ifM (allM id checks)
 	( return (Just syncbranch)
 	, return Nothing
 	)
   where
-	checks =
-		[ not <$> isBareRepo
-		, inRepo (Git.Ref.exists syncbranch)
-		, inRepo (Git.Branch.changed branch' syncbranch)
-		]
-	syncbranch = syncBranch branch
-	branch' = maybe branch (adjBranch . originalToAdjusted branch) madj
+	syncbranch = syncBranch headbranch
+	checks = case currbranch of
+		(Just _, madj) -> 
+			let branch' = maybe headbranch (adjBranch . originalToAdjusted headbranch) madj
+			in 
+				[ not <$> isBareRepo
+				, inRepo (Git.Ref.exists syncbranch)
+				, inRepo (Git.Branch.changed branch' syncbranch)
+				]
+		(Nothing, _) ->
+			[ not <$> isBareRepo
+			, inRepo (Git.Ref.exists syncbranch)
+			]
 
 pushLocal :: SyncOptions -> CurrBranch -> CommandStart
 pushLocal o b = stopUnless (notOnlyAnnex o) $ do
diff --git a/doc/bugs/git_config_merge.ff__61__only_breaks_sync.mdwn b/doc/bugs/git_config_merge.ff__61__only_breaks_sync.mdwn
index 0d0e488ef..a38c8926c 100644
--- a/doc/bugs/git_config_merge.ff__61__only_breaks_sync.mdwn
+++ b/doc/bugs/git_config_merge.ff__61__only_breaks_sync.mdwn
@@ -445,3 +445,6 @@ fatal: Not possible to fast-forward, aborting.
 ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
 
 Sure! Using git-annex to keep artifacts in development repos works great usually :)
+
+> Closing as I don't think this behavior is actually a bug. [[done]]
+> --[[Joey]]
diff --git a/doc/bugs/git_config_merge.ff__61__only_breaks_sync/comment_3_3f78dd62e99f55388e415a2e2fb86a3f._comment b/doc/bugs/git_config_merge.ff__61__only_breaks_sync/comment_3_3f78dd62e99f55388e415a2e2fb86a3f._comment
new file mode 100644
index 000000000..39976671d
--- /dev/null
+++ b/doc/bugs/git_config_merge.ff__61__only_breaks_sync/comment_3_3f78dd62e99f55388e415a2e2fb86a3f._comment
@@ -0,0 +1,35 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2020-05-05T17:05:32Z"
+ content="""
+The sync man page does mention fetching and merging:
+
+	The sync process involves first committing any local changes to files
+	that have previously been added to the repository,
+	then fetching and merging the current branch
+
+Not that I really buy the argument that not mentioning use of some specific git
+command means that it should bypass git configurations that apply to that
+command. git commands often don't document other git commands that they use
+as plumbing, for example.
+
+The output with this configuration is essentially:
+
+	pull repo-b
+	fatal: Not possible to fast-forward, aborting.
+	failed
+
+So the user is told right there that sync tried to pull.
+And the pull failed. Why? Something to do with fast-forward. While this would
+be clearer if git mentioned the config that is making it require a fast-forward,
+it does not seem an indecipherable behavior.
+
+And also, you have to have *globally* configured an option that prevents fast forwarding.
+That is a major, massive change to git's behavior. git is going to be falling over on
+pull all the time in many circumstances with the same error message.
+
+Similarly, if you had configured merge.verifySignatures globally, git-annex
+sync would be likely to fail. All your arguments would seem to require I also
+override that option. But that could be a big security hole.
+"""]]
diff --git a/doc/bugs/git_config_merge.ff__61__only_breaks_sync/comment_4_1b7133c5915baabb3076e95f0ac9807a._comment b/doc/bugs/git_config_merge.ff__61__only_breaks_sync/comment_4_1b7133c5915baabb3076e95f0ac9807a._comment
new file mode 100644
index 000000000..a3ad330a4
--- /dev/null
+++ b/doc/bugs/git_config_merge.ff__61__only_breaks_sync/comment_4_1b7133c5915baabb3076e95f0ac9807a._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2020-05-05T17:27:31Z"
+ content="""
+As to the "fatal: ambiguous argument" message, it happens in the same test
+case w/o that global git config.
+
+	[2020-05-05 13:28:27.204706608] read: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","log","refs/heads/master..refs/heads/synced/master","--pretty=%H","-n1"]
+	fatal: ambiguous argument 'refs/heads/master..refs/heads/synced/master': unknown revision or path not in the working tree.
+
+It's caused by sync being run with no master branch yet, and nothing to commit
+to create one. refs/heads/synced/master does exist; it was synced from the
+other repo. Fixed that message.
+"""]]

remove misplaced comments
an installation page is not a catch-all for random questions, or a
comprehensive link farm for documentation
diff --git a/doc/install/comment_10_a949bc4faa61f59021e896101efecb30._comment b/doc/install/comment_10_a949bc4faa61f59021e896101efecb30._comment
deleted file mode 100644
index a2a69bae4..000000000
--- a/doc/install/comment_10_a949bc4faa61f59021e896101efecb30._comment
+++ /dev/null
@@ -1,16 +0,0 @@
-[[!comment format=mdwn
- username="eric.w@eee65cd362d995ced72640c7cfae388ae93a4234"
- nickname="eric.w"
- avatar="http://cdn.libravatar.org/avatar/8d9808c12db3a3f93ff7f9e74c0870fc"
- subject="comment 10"
- date="2020-03-11T19:30:31Z"
- content="""
-Just in case someone ends up here from google... 
-
-here are the release notes for git-annex
-
-https://hackage.haskell.org/package/git-annex-8.20200309/changelog
-
-my question was answered elsewhere, so I am just adding the link to this thread.
-
-"""]]
diff --git a/doc/install/comment_9_b25b61f63a90b777e9669b36d9189f3c._comment b/doc/install/comment_9_b25b61f63a90b777e9669b36d9189f3c._comment
deleted file mode 100644
index 4b58fa675..000000000
--- a/doc/install/comment_9_b25b61f63a90b777e9669b36d9189f3c._comment
+++ /dev/null
@@ -1,15 +0,0 @@
-[[!comment format=mdwn
- username="eric.w@eee65cd362d995ced72640c7cfae388ae93a4234"
- nickname="eric.w"
- avatar="http://cdn.libravatar.org/avatar/8d9808c12db3a3f93ff7f9e74c0870fc"
- subject="where are the release notes for git annex?"
- date="2020-03-11T17:09:46Z"
- content="""
-and details like what are high level differences between v6 / v7 / v8?
-
-such as, is v7 \"stable\" and v8 \"beta\" ? this info seems to be no where on this site. 
-
-(git-annex/ assistant) has release notes, why do we have to go to (git-annex/news ?!?!!) for the same?
-
-I've been looking for this info for awhile now, I really don't get this omission. 
-"""]]

close
diff --git a/doc/bugs/dotfiles_handled_differently.mdwn b/doc/bugs/dotfiles_handled_differently.mdwn
index 2ef57c136..cdfbad6d4 100644
--- a/doc/bugs/dotfiles_handled_differently.mdwn
+++ b/doc/bugs/dotfiles_handled_differently.mdwn
@@ -30,3 +30,7 @@ Untracked files:
 
 # End of transcript or log.
 """]]
+
+> There have been several changes to dotfiles since this bug was filed. I
+> think most relevantly, annex.dotfiles can be set to let annex.largefiles
+> control them too. So this seems [[done]] --[[Joey]]

response
diff --git a/doc/bugs/git-annex_remotedaemon_--foreground_exits_immediately_if_run_as_systemd_service/comment_3_9b3040c521ec1992ec03c06a579dd627._comment b/doc/bugs/git-annex_remotedaemon_--foreground_exits_immediately_if_run_as_systemd_service/comment_3_9b3040c521ec1992ec03c06a579dd627._comment
new file mode 100644
index 000000000..cbafe3128
--- /dev/null
+++ b/doc/bugs/git-annex_remotedaemon_--foreground_exits_immediately_if_run_as_systemd_service/comment_3_9b3040c521ec1992ec03c06a579dd627._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2020-05-05T16:40:36Z"
+ content="""
+As I said, the purpose of the --foreground option is to enable a line-based
+protocol using stdin. The assistant uses that. Other things could too, I
+don't know. It's a documented interface.
+
+Yes, if you run the remotedaemon for tor, you typically don't pass that
+option, and so it does not use stdin. But an option to run in the foreground
+like that would need to be a different option than the already existing,
+documented, and used --foreground option.
+
+So, this is not a bug report, it's a feature request.
+"""]]

improve docs
diff --git a/doc/bugs/p2p_auth_token_can_only_be_retrieved_at_generation_time.mdwn b/doc/bugs/p2p_auth_token_can_only_be_retrieved_at_generation_time.mdwn
index 616ae3eff..5d0eeecd4 100644
--- a/doc/bugs/p2p_auth_token_can_only_be_retrieved_at_generation_time.mdwn
+++ b/doc/bugs/p2p_auth_token_can_only_be_retrieved_at_generation_time.mdwn
@@ -7,3 +7,6 @@ But what am I supposed to do if I want to pair a third machine later? I do not w
 So we lack a command like `git annex p2p --show-address` that just prints the same as `--gen-address`. This is trivial since we just need to concatenate `.git/annex/creds/p2paddrs`, a colon and `.git/annex/creds/p2pauth`?
 
 Actually this would be a fun starter project for a new contributor to git-annex? (me?)
+
+> I added a mention to the docs that --gen-address can be run more than
+> once, so [[done]] I suppose --[[Joey]]
diff --git a/doc/git-annex-p2p.mdwn b/doc/git-annex-p2p.mdwn
index 060ce5da8..c485f9367 100644
--- a/doc/git-annex-p2p.mdwn
+++ b/doc/git-annex-p2p.mdwn
@@ -44,6 +44,9 @@ services.
   
   Note that anyone who knows these addresses can access your
   repository over the P2P networks.
+  
+  This can be run repeatedly, in order to give different addresses 
+  out to different people.
 
 * `--link`
 

comment
diff --git a/doc/todo/document_git-annex_dependencies/comment_3_ac0b1db3d447240b49686920a71ff91b._comment b/doc/todo/document_git-annex_dependencies/comment_3_ac0b1db3d447240b49686920a71ff91b._comment
new file mode 100644
index 000000000..33262f99a
--- /dev/null
+++ b/doc/todo/document_git-annex_dependencies/comment_3_ac0b1db3d447240b49686920a71ff91b._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2020-05-05T16:32:06Z"
+ content="""
+gsasl was an indirect dependency of a ssl dependency, iirc it was dropped
+when xmpp support was removed although I could be mistaken.
+"""]]

response
diff --git a/doc/forum/How_to_fix_bad_merge/comment_1_4a32a727560ab85203d1dd76feff2e1e._comment b/doc/forum/How_to_fix_bad_merge/comment_1_4a32a727560ab85203d1dd76feff2e1e._comment
new file mode 100644
index 000000000..6af1305db
--- /dev/null
+++ b/doc/forum/How_to_fix_bad_merge/comment_1_4a32a727560ab85203d1dd76feff2e1e._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2020-05-05T16:28:32Z"
+ content="""
+Find the commit that deleted the files (eg with `git log --stat`)
+and `git revert` that commit.
+
+AKA, same way you would deal with a problem commit in any git repository.
+"""]]

update
diff --git a/doc/thanks/list b/doc/thanks/list
index f0a43bae9..d5b0836e3 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -94,3 +94,4 @@ Simon Michael,
 Stephan Burkhardt, 
 Thomas, 
 visnescire, 
+Graham Spencer, 

Revert "update"
This reverts commit f8b9b98ca878ea4426d40e075b07b408581ff7e1.
Broken script due to patreon changes..
diff --git a/doc/thanks/list b/doc/thanks/list
index 37233c0ce..f0a43bae9 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -94,43 +94,3 @@ Simon Michael,
 Stephan Burkhardt, 
 Thomas, 
 visnescire, 
-Jake, 
-Graham, 
-Denis, 
-Jochen, 
-Svenne, 
-Brock, 
-Jack, 
-Brett, 
-Boyd, 
-Ryan, 
-Markus, 
-Kuno, 
-Ewen, 
-Michal, 
-Brennen, 
-Eric, 
-David, 
-Baldur, 
-Diederik, 
-Jason, 
-Jelmer, 
-William, 
-Nathan, 
-Silvio, 
-EVAN, 
-John, 
-Nicolas, 
-Henrik, 
-James, 
-Eskild, 
-Daniel, 
-Rian, 
-Nick, 
-Lars, 
-Willard, 
-Erik, 
-Johannes, 
-Michael, 
-Luke, 
-paul, 

update
diff --git a/doc/thanks/list b/doc/thanks/list
index f0a43bae9..37233c0ce 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -94,3 +94,43 @@ Simon Michael,
 Stephan Burkhardt, 
 Thomas, 
 visnescire, 
+Jake, 
+Graham, 
+Denis, 
+Jochen, 
+Svenne, 
+Brock, 
+Jack, 
+Brett, 
+Boyd, 
+Ryan, 
+Markus, 
+Kuno, 
+Ewen, 
+Michal, 
+Brennen, 
+Eric, 
+David, 
+Baldur, 
+Diederik, 
+Jason, 
+Jelmer, 
+William, 
+Nathan, 
+Silvio, 
+EVAN, 
+John, 
+Nicolas, 
+Henrik, 
+James, 
+Eskild, 
+Daniel, 
+Rian, 
+Nick, 
+Lars, 
+Willard, 
+Erik, 
+Johannes, 
+Michael, 
+Luke, 
+paul, 

diff --git a/doc/forum/How_to_fix_bad_merge.mdwn b/doc/forum/How_to_fix_bad_merge.mdwn
new file mode 100644
index 000000000..48b748610
--- /dev/null
+++ b/doc/forum/How_to_fix_bad_merge.mdwn
@@ -0,0 +1,7 @@
+I stuffed up the [android_sync_with_adb instructions](https://git-annex.branchable.com/tips/android_sync_with_adb) and not for the first time, ending up with everything deleted from my annex except what was on my phone.
+
+I think I previously fixed it with a 'git reset --hard' however this time it has spread to all my annexes. And every time I sync the wrong situation is restored.
+
+I know I haven't lost any files, but how can I get the symlinks back the way they were?
+
+What branches do I need to reset on which repositories?