Recent changes to this wiki:

Added a comment: another instance of git-annex-sync not being idempotent
diff --git a/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_3_2381583c924561cbe46186fbd8fbf654._comment b/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_3_2381583c924561cbe46186fbd8fbf654._comment
new file mode 100644
index 000000000..35e0feef6
--- /dev/null
+++ b/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_3_2381583c924561cbe46186fbd8fbf654._comment
@@ -0,0 +1,120 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="another instance of git-annex-sync not being idempotent"
+ date="2019-08-20T17:08:45Z"
+ content="""
+Here it is again:
+
+[[!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
+
+(master_env_v152_py36) 13:01  [viral-ngs-benchmarks] $ git annex sync
+On branch is-import-rabies200
+Your branch is up to date with 'origin/is-import-rabies200'.
+
+
+It took 6.38 seconds to enumerate untracked files. 'status -uno'
+may speed it up, but you have to be careful not to forget to add
+new files yourself (see 'git help status').
+nothing to commit, working tree clean
+commit ok
+remote: Enumerating objects: 2, done.
+remote: Counting objects: 100% (2/2), done.
+remote: Compressing objects: 100% (2/2), done.
+remote: Total 2 (delta 0), reused 1 (delta 0), pack-reused 0
+Unpacking objects: 100% (2/2), done.
+From github.com:broadinstitute/viral-ngs-benchmarks
+   456ce673f18..c365f519845  is-import-rabies200        -> origin/is-import-rabies200
+   456ce673f18..c365f519845  synced/is-import-rabies200 -> origin/synced/is-import-rabies200
+Updating 456ce673f18..c365f519845
+Fast-forward
+ viral-ngs | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Already up to date.
+pull origin ok
+(master_env_v152_py36) 13:01  [viral-ngs-benchmarks] $ git annex sync
+[is-import-rabies200 fe351a22089] git-annex in viral-ngs-benchmarks copy at /data/ilya-work/benchmarks/viral-ngs-benchmarks
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+commit ok
+pull origin ok
+Enumerating objects: 3, done.
+Counting objects: 100% (3/3), done.
+Delta compression using up to 8 threads
+Compressing objects: 100% (2/2), done.
+Writing objects: 100% (2/2), 959 bytes | 959.00 KiB/s, done.
+Total 2 (delta 1), reused 0 (delta 0)
+remote: Resolving deltas: 100% (1/1), completed with 1 local object.
+To github.com:broadinstitute/viral-ngs-benchmarks.git
+   c365f519845..fe351a22089  is-import-rabies200 -> synced/is-import-rabies200
+push origin ok
+(master_env_v152_py36) 13:02  [viral-ngs-benchmarks] $ git annex sync
+On branch is-import-rabies200
+Your branch is up to date with 'origin/is-import-rabies200'.
+
+
+It took 6.40 seconds to enumerate untracked files. 'status -uno'
+may speed it up, but you have to be careful not to forget to add
+new files yourself (see 'git help status').
+nothing to commit, working tree clean
+commit ok
+pull origin ok
+(master_env_v152_py36) 13:04  [viral-ngs-benchmarks] $ uname -a
+Linux ip-172-31-93-72.ec2.internal 4.14.133-113.112.amzn2.x86_64 #1 SMP Tue Jul 30 18:29:50 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
+(master_env_v152_py36) 13:05  [viral-ngs-benchmarks] $ git annex version
+git-annex version: 7.20190819-ge4cecf8
+build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
+dependency versions: aws-0.21.1 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-sql\
+ite-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_2\
+24 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE\
+2B224E 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
+
+(master_env_v152_py36) 13:05  [viral-ngs-benchmarks] $ git remote -vv
+dnanexus
+from-ilya-work
+from-ilya-work-01
+from-ilya-work-02
+from-ilya-work-03
+ilya-work       /data/ilya-work (fetch)
+ilya-work       /data/ilya-work (push)
+my-ldir
+mygs
+origin  git@github.com:broadinstitute/viral-ngs-benchmarks.git (fetch)
+origin  git@github.com:broadinstitute/viral-ngs-benchmarks.git (push)
+s3-viral-ngs-benchmarks-web
+viral-ngs-benchmarks-s3
+
+(master_env_v152_py36) 13:06  [viral-ngs-benchmarks] $ git annex info --fast
+repository mode: indirect
+trusted repositories: 0
+semitrusted repositories: 11
+        00000000-0000-0000-0000-000000000001 -- web
+        00000000-0000-0000-0000-000000000002 -- bittorrent
+        0928dfcc-4dbe-4c24-a5a0-ac05c4a2c829 -- ilya-work
+        0f104e0a-7126-4a4a-a342-e1bb049643f0 -- [from-ilya-work-03]
+        1a276c39-67e3-4098-b469-747ab29fb97e -- viral-ngs-benchmarks copy on /ilya
+        380286ac-2e8f-4285-94da-406eca323411 -- [dnanexus]
+        40d047cf-3548-42d4-bdb6-e1e89a83b6df -- viral-ngs-benchmarks in broad laptop vm clone
+        449efa47-a0e1-4376-a17f-42c7a1f509d1 -- Benchmarks for viral-ngs, stored on Amazon S3 [viral-ngs-benchmarks-s3]
+        6b9993bb-df07-4409-be5e-05c1cd528165 -- [mygs]
+        7205b5c0-4475-47c1-bfc1-39f57a487ac4 -- Website displaying benchmark summaries, stored on AWS S3 [s3-viral-ngs-benchmarks-web]
+        b11d667d-2f3a-432a-a167-d90a1b0559cf -- viral-ngs-benchmarks copy at /data/ilya-work/benchmarks/viral-ngs-benchmarks [here]
+untrusted repositories: 1
+        b9f389c1-2a37-4200-96d9-0f07d97b5417 -- [my-ldir]
+transfers in progress: none
+available local disk space: 427.31 gigabytes (+10 gigabytes reserved)
+
+
+# End of transcript or log.
+\"\"\"]]
+
+
+"""]]

added a hyperlink to conda installation page
diff --git a/doc/install/conda.mdwn b/doc/install/conda.mdwn
index cd7911d1e..06b8ab7a7 100644
--- a/doc/install/conda.mdwn
+++ b/doc/install/conda.mdwn
@@ -2,7 +2,7 @@ On Linux, an up-to-date binary distribution of git-annex can now be
 installed with the [conda package manager](https://conda.io/docs/) 
 from the [conda-forge channel](https://conda-forge.org/).
 
-After installing conda, run:
+After [installing conda](https://docs.conda.io/en/latest/miniconda.html), run:
 
 	conda install -c conda-forge git-annex
 

Added a comment: hourly windows autobuild seems to have stopped running
diff --git a/doc/install/Windows/comment_7_0589dd8c33572dd1d0ef5cb7b29ebba7._comment b/doc/install/Windows/comment_7_0589dd8c33572dd1d0ef5cb7b29ebba7._comment
new file mode 100644
index 000000000..cb738b327
--- /dev/null
+++ b/doc/install/Windows/comment_7_0589dd8c33572dd1d0ef5cb7b29ebba7._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="hourly windows autobuild seems to have stopped running"
+ date="2019-08-19T19:47:06Z"
+ content="""
+The hourly windows autobuild seems to be several days old?
+"""]]

add news item for git-annex 7.20190819
diff --git a/doc/news/version_7.20190507.mdwn b/doc/news/version_7.20190507.mdwn
deleted file mode 100644
index be25f04bd..000000000
--- a/doc/news/version_7.20190507.mdwn
+++ /dev/null
@@ -1,6 +0,0 @@
-git-annex 7.20190507 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Fix reversion in last release that caused wrong tree to be written
-     to remote tracking branch after an export of a subtree.
-   * Improved locking when multiple git-annex processes are writing to
-     the .git/index file"""]]
\ No newline at end of file
diff --git a/doc/news/version_7.20190819.mdwn b/doc/news/version_7.20190819.mdwn
new file mode 100644
index 000000000..7bf9df631
--- /dev/null
+++ b/doc/news/version_7.20190819.mdwn
@@ -0,0 +1,37 @@
+git-annex 7.20190819 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * New git-lfs special remote, which can be used to store data on any git-lfs
+     server, including github, gitlab, and gogs.
+   * Support fully encrypting all data sent to a git-lfs special remote,
+     using a combination of gcrypt to encrypt the git data, and git-annex's
+     encryption of its data.
+   * Use the same optimisation for --in=here as has always been
+     used for --in=. rather than the slow code path that unncessarily
+     queries the git-annex branch.
+   * Allow setting up a gcrypt special remote with encryption=shared.
+   * Fix querying git for object type when operating on a file containing
+     newlines.
+   * merge: When run with a branch parameter, merges from that branch.
+     This is especially useful when using an adjusted branch, because
+     it applies the same adjustment to the branch before merging it.
+   * init: Install working hook scripts when run on a crippled filesystem
+     and on Windows. If your repository was set up by an old version
+     of git-annex that omitted the hooks, you can simply re-run git-annex init
+     to install them.
+   * init: When the repo is already initialized, and --version requests a
+     different version, error out rather than silently not changing the
+     version.
+   * S3: Fix encoding when generating public urls of S3 objects.
+   * Make git-annex-standalone.deb include the shell completions again.
+   * Makefile: Changed default zsh completion location to zsh default fpath.
+     Systems such as Debian that have overridden the default fpath will
+     need to set ZSH\_COMPLETIONS\_PATH.
+   * test: Add pass using adjusted unlocked branch.
+   * Fix intermittent failure of the test suite, where its repeated opening
+     and writing to the sqlite database somehow caused inode cache information
+     to occasionally be lost.
+   * Fix several test suite failures on Windows.
+   * Windows installer: Always install to 64 bit program files directory,
+     since it needs 64 bit git now.
+   * Build with silently-1.2.5.1 on Windows; the old one used "NUL" device
+     which is not supported with recent versions of ghc."""]]
\ No newline at end of file

Makefile: Changed default zsh completion location to zsh default fpath.
Systems such as Debian that have overridden the default fpath will need to
set ZSH_COMPLETIONS_PATH.
I feel that Debian is causing unncessary complexity by making this change,
and have filed a bug report about it.
This also means that when git-annex is installed with PREFIX=/usr/local
it will use /usr/local/share/zsh/site-functions which works with probably
all versions of zsh.
diff --git a/CHANGELOG b/CHANGELOG
index 3dd9b1cb1..c19da5a9f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -32,6 +32,9 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
     and writing to the sqlite database somehow caused inode cache information
     to occasionally be lost.
   * Make git-annex-standalone.deb include the shell completions again.
+  * Makefile: Changed default zsh completion location to zsh default fpath.
+    Systems such as Debian that have overridden the default fpath will
+    need to set ZSH_COMPLETIONS_PATH.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Makefile b/Makefile
index e5b9fef68..516f981e8 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,10 @@ endif
 PREFIX?=/usr
 SHAREDIR?=share
 
+# On Debian systems, zsh does not look here, and you will have to override
+# this to /usr/share/zsh/vendor-completions
+ZSH_COMPLETIONS_PATH?=$(PREFIX)/$(SHAREDIR)/zsh/site-functions
+
 # Am I typing :make in vim? Do a fast build.
 ifdef VIM
 all=fast
@@ -77,9 +81,9 @@ install-desktop: build Build/InstallDesktopFile
 install-completions: build
 	install -d $(DESTDIR)$(PREFIX)/$(SHAREDIR)/bash-completion/completions
 	install -m 0644 bash-completion.bash $(DESTDIR)$(PREFIX)/$(SHAREDIR)/bash-completion/completions/git-annex
-	install -d $(DESTDIR)$(PREFIX)/$(SHAREDIR)/zsh/vendor-completions
+	install -d $(DESTDIR)$(ZSH_COMPLETIONS_PATH)
 	./git-annex --zsh-completion-script git-annex 2>/dev/null \
-		> $(DESTDIR)$(PREFIX)/$(SHAREDIR)/zsh/vendor-completions/_git-annex
+		> $(DESTDIR)$(ZSH_COMPLETIONS_PATH)/_git-annex
 	install -d $(DESTDIR)$(PREFIX)/$(SHAREDIR)/fish/completions
 	./git-annex --fish-completion-script git-annex 2>/dev/null \
 		> $(DESTDIR)$(PREFIX)/$(SHAREDIR)/fish/completions/git-annex.fish
diff --git a/debian/rules b/debian/rules
index 757422dab..ad0cef7bc 100755
--- a/debian/rules
+++ b/debian/rules
@@ -11,6 +11,8 @@ STANDALONE_BUILD=$(shell grep -qe '^Package: git-annex-standalone' debian/contro
 # Do use the changelog's version number, rather than making one up.
 export RELEASE_BUILD=1
 
+export ZSH_COMPLETIONS_PATH=/usr/share/zsh/vendor-completions
+
 %:
 	dh $@
 
diff --git a/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn
index f9347b2cd..1a80aa227 100644
--- a/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn
+++ b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn
@@ -17,3 +17,5 @@ version 7.20190730 on an Arch Linux system.
 ### Recommended fix
 
 Make the installation directory configurable. Use /etc/os-release to check if the system is a Debian-based system, and if so, continue to use vendor-completions, if not, use site-functions.
+
+> [[fixed|done]] --[[Joey]]

Added a comment: storing checksums for non-checksum keys in metadata
diff --git a/doc/bugs/URL_key_potential_data_loss/comment_1_a921dab2c4335f690df4d5189fe4e4c2._comment b/doc/bugs/URL_key_potential_data_loss/comment_1_a921dab2c4335f690df4d5189fe4e4c2._comment
new file mode 100644
index 000000000..b95259669
--- /dev/null
+++ b/doc/bugs/URL_key_potential_data_loss/comment_1_a921dab2c4335f690df4d5189fe4e4c2._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="storing checksums for non-checksum keys in metadata"
+ date="2019-08-16T16:06:29Z"
+ content="""
+One related improvement would be for git-annex to compute and store, as metadata, checksum-based [[keys|backends]] corresponding to non-checksum-based keys, when git-annex sees the contents of the non-checksum-based key ( e.g. [[todo/alternate_keys_for_same_content]] ). There is of course [[`git-annex-migrate`|git-annex-migrate]], but it requires manual invocation, clouds the commit history of the main git branch with commits that don't really change the content, and leads to either duplicate content in remotes or (if duplicates are dropped) inability to git-annex-get the contents of some past commits.
+"""]]

removed
diff --git a/doc/bugs/URL_key_potential_data_loss/comment_1_505eb7cf1da3e63e5e4f018391712761._comment b/doc/bugs/URL_key_potential_data_loss/comment_1_505eb7cf1da3e63e5e4f018391712761._comment
deleted file mode 100644
index 0bb26b27f..000000000
--- a/doc/bugs/URL_key_potential_data_loss/comment_1_505eb7cf1da3e63e5e4f018391712761._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="Ilya_Shlyakhter"
- avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
- subject="storing checksums for non-checksum keys in metadata"
- date="2019-08-16T16:02:41Z"
- content="""
-One related improvement would be for git-annex to compute and store, as metadata, checksum-based keys corresponding to non-checksum-based keys, when git-annex sees the contents of the non-checksum-based key ( e.g. [todo/alternate_keys_for_same_content]] ).  There is of course [[git-annex-migrate]], but it requires manual invocation, clouds the commit history of the main git branch with commits that don't really change the content, and leads to either duplicate content in remotes or (if duplicates are dropped) inability to git-annex-get the contents of some past commits.
-"""]]

Added a comment: storing checksums for non-checksum keys in metadata
diff --git a/doc/bugs/URL_key_potential_data_loss/comment_1_505eb7cf1da3e63e5e4f018391712761._comment b/doc/bugs/URL_key_potential_data_loss/comment_1_505eb7cf1da3e63e5e4f018391712761._comment
new file mode 100644
index 000000000..0bb26b27f
--- /dev/null
+++ b/doc/bugs/URL_key_potential_data_loss/comment_1_505eb7cf1da3e63e5e4f018391712761._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="storing checksums for non-checksum keys in metadata"
+ date="2019-08-16T16:02:41Z"
+ content="""
+One related improvement would be for git-annex to compute and store, as metadata, checksum-based keys corresponding to non-checksum-based keys, when git-annex sees the contents of the non-checksum-based key ( e.g. [todo/alternate_keys_for_same_content]] ).  There is of course [[git-annex-migrate]], but it requires manual invocation, clouds the commit history of the main git branch with commits that don't really change the content, and leads to either duplicate content in remotes or (if duplicates are dropped) inability to git-annex-get the contents of some past commits.
+"""]]

add missing build dep of install-completions
Since it runs git-annex to generate the completions files.
diff --git a/Makefile b/Makefile
index e61a99608..8a3cc5da3 100644
--- a/Makefile
+++ b/Makefile
@@ -74,7 +74,7 @@ install-bins: build
 install-desktop: build Build/InstallDesktopFile
 	./Build/InstallDesktopFile $(PREFIX)/bin/git-annex || true
 
-install-completions:
+install-completions: build
 	install -d $(DESTDIR)$(PREFIX)/$(SHAREDIR)/bash-completion/completions
 	install -m 0644 bash-completion.bash $(DESTDIR)$(PREFIX)/$(SHAREDIR)/bash-completion/completions/git-annex
 	install -d $(DESTDIR)$(PREFIX)/$(SHAREDIR)/zsh/vendor-completions
diff --git a/doc/bugs/install-completions_target_has_missing_dependency.mdwn b/doc/bugs/install-completions_target_has_missing_dependency.mdwn
index 8a0b4835b..101cafd67 100644
--- a/doc/bugs/install-completions_target_has_missing_dependency.mdwn
+++ b/doc/bugs/install-completions_target_has_missing_dependency.mdwn
@@ -15,3 +15,5 @@ https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/
 reference downstream bug: https://bugs.archlinux.org/task/62775
 
 (This is building the binary via runhaskell Setup configure/build instead of using the Makefile -- I don't know exactly why, but I suspect it was originally packaged that way due to needing custom options for Arch's ghc.)
+
+> [[fixed|done]] --[[Joey]]

add comment
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_7_2181d91c9b5b374c6102fdcc227349fc._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_7_2181d91c9b5b374c6102fdcc227349fc._comment
new file mode 100644
index 000000000..eed970fd3
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_7_2181d91c9b5b374c6102fdcc227349fc._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2019-08-16T15:03:11Z"
+ content="""
+Confirmed; avoiding calling main has gotten the test suite to be able to
+run at least 500 iterations over 12 hours w/o failing. It had been failing
+in under 1 hour.
+"""]]

Fix intermittent failure of the test suite
Its repeated opening and writing to the sqlite database somehow caused
inode cache information to occasionally be lost.
This loses code coverage, since running git-annex as a child process
prevents tracking what parts of the code are exercised. I have not looked
at the code coverage in a long time. It would probably be possible to
collect code coverage for the child procesess and merge it together.
diff --git a/CHANGELOG b/CHANGELOG
index a9a3dbd1e..c4a708d4c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,6 +28,9 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
     of git-annex that omitted the hooks, you can simply re-run git-annex init
     to install them.
   * S3: Fix encoding when generating public urls of S3 objects.
+  * Fix intermittent failure of the test suite, where its repeated opening
+    and writing to the sqlite database somehow caused inode cache information
+    to occasionally be lost.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Test/Framework.hs b/Test/Framework.hs
index b50538d60..bb5ca446c 100644
--- a/Test/Framework.hs
+++ b/Test/Framework.hs
@@ -42,47 +42,26 @@ import qualified Utility.Exception
 import qualified Utility.ThreadScheduler
 import qualified Utility.Tmp.Dir
 import qualified Utility.Metered
+import qualified Utility.SafeCommand
 import qualified Command.Uninit
-import qualified CmdLine.GitAnnex as GitAnnex
 
--- This is equivilant to running git-annex, but it's all run in-process
--- so test coverage collection works.
+-- Run git-annex.
 git_annex :: String -> [String] -> IO Bool
-git_annex command params = git_annex' command params >>= \case
-	Right () -> return True
-	Left e -> do
-		hPutStrLn stderr (show e)
-		return False
+git_annex command params = do
+	pp <- Annex.Path.programPath
+	Utility.SafeCommand.boolSystem pp $
+		map Utility.SafeCommand.Param (command:params)
 
 -- For when git-annex is expected to fail.
+-- Run with -q to squelch error.
 git_annex_shouldfail :: String -> [String] -> IO Bool
-git_annex_shouldfail command params = git_annex' command ("-q":params) >>= \case
-	Right () -> return False
-	Left _ -> return True
-
-git_annex' :: String -> [String] -> IO (Either SomeException ())
-git_annex' command params = do
-	-- catch all errors, including normally fatal errors
-	try run ::IO (Either SomeException ())
-  where
-	run = GitAnnex.run dummyTestOptParser
-		dummyTestRunner
-		dummyBenchmarkGenerator
-		(command:params)
-	dummyTestOptParser = pure mempty
-	dummyTestRunner _ = noop
-	dummyBenchmarkGenerator _ _ = return noop
+git_annex_shouldfail command params = not <$> git_annex command ("-q":params)
 
 {- Runs git-annex and returns its output. -}
 git_annex_output :: String -> [String] -> IO String
 git_annex_output command params = do
 	pp <- Annex.Path.programPath
-	got <- Utility.Process.readProcess pp (command:params)
-	-- Since the above is a separate process, code coverage stats are
-	-- not gathered for things run in it.
-	-- Run same command again, to get code coverage.
-	_ <- git_annex command params
-	return got
+	Utility.Process.readProcess pp (command:params)
 
 git_annex_expectoutput :: String -> [String] -> [String] -> IO ()
 git_annex_expectoutput command params expected = do
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn b/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
index 6f482509e..c6da04ff1 100644
--- a/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
@@ -31,3 +31,5 @@ FAIL (0.34s)
 I have tried to rebuild (`debian/rules binary`) second time while in the same environment -- didn't succeed... but then I proceeded to build amd64 fine, and redid i386 build just fine
 
 [[!meta author=yoh]]
+
+> [[fixed|done]] though w/o a true root cause analysis --[[Joey]]

use GHC not ghc
diff --git a/Makefile b/Makefile
index d202fba4a..e61a99608 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ install-home:
 	$(MAKE) install-desktop PREFIX=$(HOME)/.local USERDIR=1
 
 tmp/configure-stamp: Build/TestConfig.hs Build/Configure.hs
-	if [ "$(BUILDER)" = ./Setup ]; then ghc --make Setup; fi
+	if [ "$(BUILDER)" = ./Setup ]; then $(GHC) --make Setup; fi
 	if [ "$(BUILDER)" != stack ]; then \
 		$(BUILDER) configure $(BUILDERCOMMONOPTIONS) --ghc-options="$(shell Build/collect-ghc-options.sh)"; \
 	else \
diff --git a/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn b/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn
index 0e3d03bf4..844ca57c4 100644
--- a/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn
+++ b/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn
@@ -10,3 +10,4 @@ Arch Linux doesn't ship with static libraries of ghc boot libraries by default,
 ### 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!
 
+> [[fixed|done]] --[[Joey]]

diff --git a/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn b/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn
new file mode 100644
index 000000000..0e3d03bf4
--- /dev/null
+++ b/doc/bugs/Makefile_should_use___36____40__GHC__41___to_run_ghc_--make.mdwn
@@ -0,0 +1,12 @@
+### Please describe the problem.
+In line 32, Makefile runs "ghc --make Setup" which ignores the variable $(GHC).
+
+### What steps will reproduce the problem?
+Arch Linux doesn't ship with static libraries of ghc boot libraries by default, so I am passing GHC="ghc -dynamic" to Makefile, which sadly doesn't work as intended.
+
+### What version of git-annex are you using? On what operating system?
+7.20190730
+
+### 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!
+

comment
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_6_357f297d1afab22a59b2bafe4b85facd._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_6_357f297d1afab22a59b2bafe4b85facd._comment
new file mode 100644
index 000000000..9ddaea9d5
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_6_357f297d1afab22a59b2bafe4b85facd._comment
@@ -0,0 +1,36 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2019-08-15T21:55:43Z"
+ content="""
+It is indeed detecting that the file it was sending
+appears to have been modified after the download started.
+
+Probably the file has not really been modified. Instead the inode cache
+for it is somehow wrong.
+
+An instrumented run had cached:
+
+	InodeCache (InodeCachePrim 21765306 20 (MTimeHighRes 1565905801.196804558s)
+	InodeCache (InodeCachePrim 22158907 20 (MTimeHighRes 1565905801.196804558s))
+
+And after the download the file it was sending had:
+
+	InodeCache (InodeCachePrim 21765305 20 (MTimeHighRes 1565905802.380791792s))
+
+Note that the test suite moves the same file from origin,
+and then moves it back, and a while after that get fails.
+So at least one of the cached inodes is for the old copy of the file.
+The other one is probably the work tree copy.
+
+Still have not had luck reproducing outside the test suite with a tight loop
+of move --from and --to and get.
+
+Hypothesis: The test suite uses Annex.main for many of its runs of git-annex,
+and so sqlite does not do whatever it normally does atexit. If flushing
+a change to the db file gets deferred for whatever reason, a later call to
+Annex.main might see old information.
+
+If so, converting the test suite to run git-annex instead of Annex.main
+would avoid the problem.
+"""]]

diff --git a/doc/bugs/install-completions_target_has_missing_dependency.mdwn b/doc/bugs/install-completions_target_has_missing_dependency.mdwn
new file mode 100644
index 000000000..8a0b4835b
--- /dev/null
+++ b/doc/bugs/install-completions_target_has_missing_dependency.mdwn
@@ -0,0 +1,17 @@
+### Please describe the problem.
+
+When running `make install-desktop install-completions`, the git-annex binary may not exist yet. Depending on the order in which Make runs the requested targets, the git-annex target (install-desktop -> build -> $(all) -> git-annex) may or may not have run, to a) check that dist/build/git-annex/git-annex is up to date, b) create the symlink in the root directory, by the time the install-completions target gets run.
+
+### What steps will reproduce the problem?
+
+`make install-completions` without the git-annex binary having been built already.
+
+### What version of git-annex are you using? On what operating system?
+
+Trying to package git-annex for Arch Linux, using the following build recipe:
+
+https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/git-annex#n34
+
+reference downstream bug: https://bugs.archlinux.org/task/62775
+
+(This is building the binary via runhaskell Setup configure/build instead of using the Makefile -- I don't know exactly why, but I suspect it was originally packaged that way due to needing custom options for Arch's ghc.)

update
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_5_b08d8859f873fcbdc78f938042fe0fbd._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_5_b08d8859f873fcbdc78f938042fe0fbd._comment
new file mode 100644
index 000000000..86410f6bd
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_5_b08d8859f873fcbdc78f938042fe0fbd._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2019-08-15T21:18:20Z"
+ content="""
+I tested a git-annex made to say when the rsync process succeeded,
+and rsync is actually not failing.
+
+So something in git-annex is silently making the transfer fail.
+Could be, for example, that it thinks the file was modified while
+it was being transferred.
+"""]]

bug
diff --git a/doc/bugs/URL_key_potential_data_loss.mdwn b/doc/bugs/URL_key_potential_data_loss.mdwn
new file mode 100644
index 000000000..4893ce637
--- /dev/null
+++ b/doc/bugs/URL_key_potential_data_loss.mdwn
@@ -0,0 +1,32 @@
+Using URL keys can lead to data loss. Two remotes can have two different
+objects for the same URL key, as the content of an url may change over
+time. If git-annex gets part of an object from the first remote, but is
+then interrupted or fails, and then resumes from the second remote's
+object, it will stitch together a chimera that has never existed at the
+url. Then dropping the URL objects from both remotes will result in no
+valid copies of the object remaining.
+
+This could also happen with WORM, but it would be much less likely. Two
+files with the same mtime, size, and path would have to be added to two
+repos.
+
+And it could happen if an old git-annex is being used in a repo that uses
+some new key that it doesn't support, like a new checksum type.
+
+Special remotes are affected if they use chunking, or if they resume
+when the destination file already exists and don't have their own
+checksumming. So the rsync special remote is affected when it's used with
+chunking, but not otherwise.
+
+With the default annex.security.allow-unverified-downloads config, 
+encrypted special remotes already don't allow downloading the problem keys.
+
+The bug affects remotes using the git-annex P2P protocol, but not ssh remotes
+using rsync. So the introduction of the P2P protocol made this bug more
+prevelant.
+
+Best fix for this seems to be to prevent resuming download of keys 
+when their content is not verifiable.
+
+The P2P protocol could also be extended to use a checksum to verify a
+resume is safe to do. That would only be worth doing for the affected keys.

Added a comment
diff --git a/doc/bugs/zsh_completions_installed_to_location_not_in_fpath/comment_2_184598bf13c232c1e8934180bf79d364._comment b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath/comment_2_184598bf13c232c1e8934180bf79d364._comment
new file mode 100644
index 000000000..6850184cd
--- /dev/null
+++ b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath/comment_2_184598bf13c232c1e8934180bf79d364._comment
@@ -0,0 +1,35 @@
+[[!comment format=mdwn
+ username="eschwartz@5abb721e66990e478c7d1caf96beb4f9794eb168"
+ nickname="eschwartz"
+ avatar="http://cdn.libravatar.org/avatar/16ec8475b4e3507f8d1a71101c16b208"
+ subject="comment 2"
+ date="2019-08-15T21:15:09Z"
+ content="""
+The greatness of os-release (dash, not underscore) is that you can use the ID_LIKE field. From the os-release(5) man page:
+
+\"A space-separated list of operating system identifiers in the same syntax as the ID= setting. It should list identifiers of operating systems that are closely related to the local operating system in regards to packaging and programming interfaces [...]\". If \"debian\" is the value of ID, or is contained in the space-separated value of ID_LIKE, then you don't need to know what the specific OS is.
+
+Before os-release, it was common to check if the file /etc/debian_version existed, and if not, check for other distros using /etc/arch-release, /etc/fedora-release, and so on. Ubuntu historically included /etc/debian_version just so tools could identify the distro as debian-compatible, while identifying as Ubuntu only if you used lsb-release...
+
+...
+
+The site-functions directory should work everywhere, I think, since both the /usr/share and /usr/local/share equivalents are defined by the zsh build system (and I'm not aware of any distributors other than Debian which override the former). On my Arch system:
+
+```
+echo $fpath
+/usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/functions/Calendar /usr/share/zsh/functions/Chpwd /usr/share/zsh/functions/Completion /usr/share/zsh/functions/Completion/Base /usr/share/zsh/functions/Completion/Linux /usr/share/zsh/functions/Completion/Unix /usr/share/zsh/functions/Completion/X /usr/share/zsh/functions/Completion/Zsh /usr/share/zsh/functions/Exceptions /usr/share/zsh/functions/Math /usr/share/zsh/functions/MIME /usr/share/zsh/functions/Misc /usr/share/zsh/functions/Newuser /usr/share/zsh/functions/Prompts /usr/share/zsh/functions/TCP /usr/share/zsh/functions/VCS_Info /usr/share/zsh/functions/VCS_Info/Backends /usr/share/zsh/functions/Zftp /usr/share/zsh/functions/Zle
+```
+Specifically, if you look at the configure.ac, it will:
+
+- take a configurable --enable-site-fndir (the packaging location), which defaults to /usr/share/zsh/site-functions but which Debian overrides (this is SITEFPATH_DIR in Src/init.c)
+- if enable-site-fndir did not already get defined to /usr/local/share/zsh/site-functions (the local sysadmin location), then guarantee it is included by defining it as $fixed_sitefndir and embedding it in the binary as FIXED_FPATH_DIR (Src/init.c)
+- additionally include anything configured via --enable-additional-fpath, because enable-site-fndir is a string rather than an array, and the additional-fpath can be a comma-separated array (ADDITIONAL_FPATH in Src/init.c)
+
+It's regrettable that unlike bash-completion, there is no pkg-config file for this. :( That would at least allow the build system to build-depend on zsh in order to automatically grab this information. But ultimately, the only thing you need to worry about is which distribution-modified value to use for/instead of /usr/share/zsh/site-functions
+
+In the case of curl, the make install only installs to site-functions, but provides an option --with-zsh-functions-dir=/usr/share/zsh/vendor-completions used at https://salsa.debian.org/debian/curl/blob/27e07a35cb9c727d6005c0afa291e2a3dc3bc5af/debian/rules#L20
+
+Various other programs I have seen will often install to site-functions and let debian's packaging move it if needed, or try to check whether any of several known directories exist. Here is an elaborate detection mechanism which works for a proliferation of possible locations, and can be successfully packaged in a distro build recipe if you first mkdir -p \"$DESTDIR/usr/share/zsh/site-functions\" (or vendor-completions, depending): https://github.com/kovidgoyal/calibre/blob/7460a12a4bcd05efc822f7fe421626772e2f6575/src/calibre/linux.py#L192-L210
+
+The downside of that is that the packager needs to know they should do this first. :(
+"""]]

comment
diff --git a/doc/bugs/zsh_completions_installed_to_location_not_in_fpath/comment_1_82e2d63c92276bb71891f3d8cc8dc9dd._comment b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath/comment_1_82e2d63c92276bb71891f3d8cc8dc9dd._comment
new file mode 100644
index 000000000..20aba16f2
--- /dev/null
+++ b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath/comment_1_82e2d63c92276bb71891f3d8cc8dc9dd._comment
@@ -0,0 +1,27 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2019-08-15T18:52:51Z"
+ content="""
+Debian also supports /usr/local/share/zsh/site-functions/,
+it's just that it's for local sysadmin use and not a place that
+packages should install files, so they added /usr/share/zsh/vendor-completions/
+for that.
+
+However, checking `/etc/os_release` probably entails keeping track of the
+name of every debian derivative, so I'd really rather not do that.
+
+Also, even if the Makefile were changed to use
+/usr/local/share/zsh/site-functions/, it sounds as if that might not be a
+path that works universally either.
+
+Surely there must be a way to ask zsh where to install completions to?
+But short of taking the first item from $fpath, which doesn't seem robust,
+I don't know how to. And zsh may not even be installed when building a
+package that should later integrate with zsh.
+
+FWIW, I checked half a dozen packages like curl that include zsh
+completions, and none of them installed them with `make install`,
+they were just there to be installed manually. It seems zsh is making this
+too hard for software to bother integrating with it.
+"""]]

followup and display rsync exit status
diff --git a/Utility/Metered.hs b/Utility/Metered.hs
index e1cf3d38c..0fec7749b 100644
--- a/Utility/Metered.hs
+++ b/Utility/Metered.hs
@@ -210,7 +210,14 @@ type ProgressParser = String -> (Maybe BytesProcessed, String)
  - to update a meter.
  -}
 commandMeter :: ProgressParser -> OutputHandler -> MeterUpdate -> FilePath -> [CommandParam] -> IO Bool
-commandMeter progressparser oh meterupdate cmd params = 
+commandMeter progressparser oh meterupdate cmd params = do
+	ret <- commandMeter' progressparser oh meterupdate cmd params
+	return $ case ret of
+		Just ExitSuccess -> True
+		_ -> False
+
+commandMeter' :: ProgressParser -> OutputHandler -> MeterUpdate -> FilePath -> [CommandParam] -> IO (Maybe ExitCode)
+commandMeter' progressparser oh meterupdate cmd params = 
 	outputFilter cmd params Nothing
 		(feedprogress zeroBytesProcessed [])
 		handlestderr
@@ -245,9 +252,13 @@ demeterCommand :: OutputHandler -> FilePath -> [CommandParam] -> IO Bool
 demeterCommand oh cmd params = demeterCommandEnv oh cmd params Nothing
 
 demeterCommandEnv :: OutputHandler -> FilePath -> [CommandParam] -> Maybe [(String, String)] -> IO Bool
-demeterCommandEnv oh cmd params environ = outputFilter cmd params environ
-	(\outh -> avoidProgress True outh stdouthandler)
-	(\errh -> avoidProgress True errh $ stderrHandler oh)
+demeterCommandEnv oh cmd params environ = do
+	ret <- outputFilter cmd params environ
+		(\outh -> avoidProgress True outh stdouthandler)
+		(\errh -> avoidProgress True errh $ stderrHandler oh)
+	return $ case ret of
+		Just ExitSuccess -> True
+		_ -> False
   where
 	stdouthandler l = 
 		unless (quietMode oh) $
@@ -270,16 +281,15 @@ outputFilter
 	-> Maybe [(String, String)]
 	-> (Handle -> IO ())
 	-> (Handle -> IO ())
-	-> IO Bool
-outputFilter cmd params environ outfilter errfilter = catchBoolIO $ do
+	-> IO (Maybe ExitCode)
+outputFilter cmd params environ outfilter errfilter = catchMaybeIO $ do
 	(_, Just outh, Just errh, pid) <- createProcess p
 		{ std_out = CreatePipe
 		, std_err = CreatePipe
 		}
 	void $ async $ tryIO (outfilter outh) >> hClose outh
 	void $ async $ tryIO (errfilter errh) >> hClose errh
-	ret <- checkSuccessProcess pid
-	return ret
+	waitForProcess pid
   where
 	p = (proc cmd (toCommand params))
 		{ env = environ }
diff --git a/Utility/Rsync.hs b/Utility/Rsync.hs
index 25af52617..be890ca07 100644
--- a/Utility/Rsync.hs
+++ b/Utility/Rsync.hs
@@ -103,7 +103,16 @@ rsyncUrlIsPath s
  - The params must enable rsync's --progress mode for this to work.
  -}
 rsyncProgress :: OutputHandler -> MeterUpdate -> [CommandParam] -> IO Bool
-rsyncProgress oh meter = commandMeter parseRsyncProgress oh meter "rsync" . rsyncParamsFixup
+rsyncProgress oh meter ps =
+	commandMeter' parseRsyncProgress oh meter "rsync" (rsyncParamsFixup ps) >>= \case
+		Just ExitSuccess -> return True
+		Just (ExitFailure exitcode) -> do
+			when (exitcode /= 1) $
+				hPutStrLn stderr $ "rsync exited " ++ show exitcode
+			return False
+		Nothing -> do
+			hPutStrLn stderr $ "unable to run rsync"
+			return False
 
 {- Strategy: Look for chunks prefixed with \r (rsync writes a \r before
  - the first progress output, and each thereafter). The first number
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn b/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
index d0407c048..6f482509e 100644
--- a/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
@@ -1,3 +1,5 @@
+[[!meta title="double rsync run and test failure"]]
+
 might be a flaky test/operation, happened while building in i386 buster environment:
 
 [[!format sh """
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_4_8be6e27e081d4bc8c0fa178088a10a91._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_4_8be6e27e081d4bc8c0fa178088a10a91._comment
new file mode 100644
index 000000000..913b683b2
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_4_8be6e27e081d4bc8c0fa178088a10a91._comment
@@ -0,0 +1,58 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2019-08-15T18:00:42Z"
+ content="""
+And even if we assume rsync never pre-allocates a file before receiving it, it
+probably does do some things at the end, like setting the final permissions and
+timestamp.
+
+The permissions error looked like this:
+
+    get foo (from origin...)
+    SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77
+                 20 100%    0.00kB/s    0:00:00  ^M             20 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=0/1)
+    (from origin...)
+    SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77
+                 20 100%    0.00kB/s    0:00:00  ^M             20 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=0/1)
+    rsync: open "/home/joey/src/git-annex/.t/tmprepo1103/.git/annex/tmp/SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77" failed: Permission denied (13)
+    rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3]
+ 
+That looked as if the first rsync had gotten as far as removing the write bit
+from the file. Interestingly, the second rsync seems to have received the whole
+(small) file content before ever trying to open the file for write.
+
+The only recent change I can think of involving rsync was the CoW probing
+change, but I don't see how that could possibly lead to this behavior.
+
+And I'm not sure this is a new problem. The test suite has been intermittently
+failing for several months, around this same point. The failure did not
+include any useful error message, so I could not debug it, and I have IIRC
+done a few things to try to get the test suite to display an error message.
+Perhaps I succeeded.
+
+The intermittent test suite failure looks like this:
+
+	copy: [adjusted/master(unlocked) 05b89a6] empty
+	adjust ok
+	copy foo (from origin...)
+	SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77
+	20 100% 0.00kB/s 0:00:00 20 100% 0.00kB/s 0:00:00 (xfr#1, to-chk=0/1)
+	
+	SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77
+	20 100% 0.00kB/s 0:00:00 20 100% 0.00kB/s 0:00:00 (xfr#1, to-chk=0/1)
+	failed
+	copy: 1 failed
+	FAIL (1.12s)
+
+I am not sure if it only happens when testing adjusted unlocked branches/
+v7 unlocked files.
+
+I've run git-annex get; git-annex drop in a tight loop for
+thousands of iterations on an adjusted unlocked branch,
+and can't reproduce the failure that way.
+
+I've made git-annex display rsync's exit status when it's not 0 or 1,
+it has a lot of other exit statuses, so perhaps that will help track
+down how it's failing.
+"""]]

New bug for zsh-completion.
diff --git a/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn
new file mode 100644
index 000000000..f9347b2cd
--- /dev/null
+++ b/doc/bugs/zsh_completions_installed_to_location_not_in_fpath.mdwn
@@ -0,0 +1,19 @@
+### Please describe the problem.
+
+Installing git-annex via the Makefile results in a zsh completion installed to `$(PREFIX)/$(SHAREDIR)/zsh/vendor-completions`
+
+This is not used by zsh, since the builtin zsh fpath is `$(PREFIX)/$(SHAREDIR)/zsh/site-functions` -- as a result, zsh completions do not work.
+
+Some system distributions of zsh may change the builtin fpath, in which case git-annex may have working zsh completions out of the box -- I believe the current installation method is designed based on Debian's preferred layout.
+
+### What steps will reproduce the problem?
+
+Install git-annex on a non-Debian system
+
+### What version of git-annex are you using? On what operating system?
+
+version 7.20190730 on an Arch Linux system.
+
+### Recommended fix
+
+Make the installation directory configurable. Use /etc/os-release to check if the system is a Debian-based system, and if so, continue to use vendor-completions, if not, use site-functions.

S3: Fix encoding when generating public urls of S3 objects.
This code feels worryingly stringily typed, but using URI does not help
because the uriPath still has to be constructed with the right
uri-encoding.
diff --git a/CHANGELOG b/CHANGELOG
index 49a85bde4..a9a3dbd1e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -27,6 +27,7 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
     and on Windows. If your repository was set up by an old version
     of git-annex that omitted the hooks, you can simply re-run git-annex init
     to install them.
+  * S3: Fix encoding when generating public urls of S3 objects.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Remote/S3.hs b/Remote/S3.hs
index a79712e31..84b4ab5c6 100644
--- a/Remote/S3.hs
+++ b/Remote/S3.hs
@@ -29,6 +29,7 @@ import Network.Socket (HostName)
 import Network.HTTP.Conduit (Manager)
 import Network.HTTP.Client (responseStatus, responseBody, RequestBody(..))
 import Network.HTTP.Types
+import Network.URI
 import Control.Monad.Trans.Resource
 import Control.Monad.Catch
 import Data.IORef
@@ -387,15 +388,15 @@ retrieveExportS3 hv r info _k loc f p =
   where
 	go = withS3Handle hv $ \case
 		Just h -> do
-			retrieveHelper info h (Left (T.pack exporturl)) f p
+			retrieveHelper info h (Left (T.pack exportloc)) f p
 			return True
 		Nothing -> case getPublicUrlMaker info of
 			Nothing -> do
 				warning $ needS3Creds (uuid r)
 				return False
 			Just geturl -> Url.withUrlOptions $ 
-				liftIO . Url.download p (geturl exporturl) f
-	exporturl = bucketExportLocation info loc
+				liftIO . Url.download p (geturl exportloc) f
+	exportloc = bucketExportLocation info loc
 
 removeExportS3 :: S3HandleVar -> Remote -> S3Info -> Key -> ExportLocation -> Annex Bool
 removeExportS3 hv r info k loc = withS3Handle hv $ \case
@@ -928,7 +929,14 @@ awsPublicUrl info = genericPublicUrl $
 	"https://" ++ T.unpack (bucket info) ++ ".s3.amazonaws.com/" 
 
 genericPublicUrl :: URLString -> BucketObject -> URLString
-genericPublicUrl baseurl p = baseurl Posix.</> p
+genericPublicUrl baseurl p = 
+	baseurl Posix.</> escapeURIString skipescape p
+ where
+	-- Don't need to escape '/' because the bucket object
+	-- is not necessarily a single url component. 
+	-- But do want to escape eg '+' and ' '
+	skipescape '/' = True
+	skipescape c = isUnescapedInURIComponent c
 
 genCredentials :: CredPair -> IO AWS.Credentials
 genCredentials (keyid, secret) = AWS.Credentials
@@ -1126,8 +1134,8 @@ eitherS3VersionID info u c k fallback
 	| otherwise = return (Right (Left fallback))
 
 s3VersionIDPublicUrl :: (S3Info -> BucketObject -> URLString) -> S3Info -> S3VersionID -> URLString
-s3VersionIDPublicUrl mk info (S3VersionID obj vid) = mk info $ concat
-	[ T.unpack obj
+s3VersionIDPublicUrl mk info (S3VersionID obj vid) = concat
+	[ mk info (T.unpack obj)
 	, "?versionId="
 	, T.unpack vid -- version ID is "url ready" so no escaping needed
 	]
diff --git a/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn b/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn
index 1f542f4df..250512fbb 100644
--- a/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn
+++ b/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn
@@ -17,3 +17,5 @@ frustratingly vague.
 
 Experimentally, even url-encoding alphanumerics works in these urls.
 So it would be ok to use a standard URI encoder.
+
+> [[fixed|done]] --[[Joey]]

bug
diff --git a/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn b/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn
new file mode 100644
index 000000000..1f542f4df
--- /dev/null
+++ b/doc/bugs/versioned_S3_generates_invalid_encoded_url.mdwn
@@ -0,0 +1,19 @@
+See https://github.com/OpenNeuroOrg/datalad-service/issues/99
+where the url generated by a versioned S3 export remote did not url-encode
+the "+" in the S3 object ID.
+
+This breaks git-annex info's display of urls for a file.
+It also breaks git-annex get from a public S3 remote. While the object
+in that issue is versioned, other code paths for non-versioned objects
+have the same problem.
+
+https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
+describes an URI encoding that appears non-standard;
+Aws.S3.Core.s3UriEncode implements that. But is S3 using the same
+non-standard URI encoding for URLs to objects?
+https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
+documents a need to url-encode a few punctuation characters, but is
+frustratingly vague.
+
+Experimentally, even url-encoding alphanumerics works in these urls.
+So it would be ok to use a standard URI encoder.

Added a comment
diff --git a/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_2_ba60267d8b34ae9e277ae992dcfcde96._comment b/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_2_ba60267d8b34ae9e277ae992dcfcde96._comment
new file mode 100644
index 000000000..7f8cb74b5
--- /dev/null
+++ b/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_2_ba60267d8b34ae9e277ae992dcfcde96._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="comment 2"
+ date="2019-08-14T18:40:49Z"
+ content="""
+It's possible that I didn't paste the output correctly (it was more than a screenful, so was pasted in two parts).  I'll post again if I see this happen again.
+"""]]

fixed
diff --git a/doc/bugs/windows_fails_import_export_tests.mdwn b/doc/bugs/windows_fails_import_export_tests.mdwn
index f502f9c96..d8861fa33 100644
--- a/doc/bugs/windows_fails_import_export_tests.mdwn
+++ b/doc/bugs/windows_fails_import_export_tests.mdwn
@@ -28,3 +28,5 @@ so the hook can be installed and will work. On Windows, a hook can start
 with #!/bin/sh and not be executable, and will be run by the bash bundled
 with git for windows.
 --[[Joey]]
+
+> [[fixed|done]]; 100% test pass on windows now --[[Joey]]

comment
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_3_09343b67a0c6e82203b76ef591233869._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_3_09343b67a0c6e82203b76ef591233869._comment
new file mode 100644
index 000000000..e5eedd372
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_3_09343b67a0c6e82203b76ef591233869._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2019-08-13T19:14:41Z"
+ content="""
+No, it cannot in general rely on that. Consider a file transfer program
+that allocates the whole file full of 0 to start.
+
+This needs to be reproduced in strace so we can see what it happening with
+rsync.
+"""]]

init: Install working hook scripts when run on a crippled filesystem and on Windows
diff --git a/Annex/Hook.hs b/Annex/Hook.hs
index 3bd958b8e..b56b3bf6c 100644
--- a/Annex/Hook.hs
+++ b/Annex/Hook.hs
@@ -13,7 +13,6 @@ module Annex.Hook where
 
 import Annex.Common
 import qualified Git.Hook as Git
-import Config
 import qualified Annex
 import Utility.Shell
 
@@ -57,11 +56,8 @@ mkHookScript s = unlines
 	]
 
 hookWrite :: Git.Hook -> Annex ()
-hookWrite h = 
-	-- cannot have git hooks in a crippled filesystem (no execute bit)
-	unlessM crippledFileSystem $
-		unlessM (inRepo $ Git.hookWrite h) $
-			hookWarning h "already exists, not configuring"
+hookWrite h = unlessM (inRepo $ Git.hookWrite h) $
+	hookWarning h "already exists, not configuring"
 
 hookUnWrite :: Git.Hook -> Annex ()
 hookUnWrite h = unlessM (inRepo $ Git.hookUnWrite h) $
diff --git a/CHANGELOG b/CHANGELOG
index 24e9bde41..49a85bde4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -23,6 +23,10 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
     it applies the same adjustment to the branch before merging it.
   * test: Add pass using adjusted unlocked branch.
   * Fix some test suite failures on Windows.
+  * init: Install working hook scripts when run on a crippled filesystem
+    and on Windows. If your repository was set up by an old version
+    of git-annex that omitted the hooks, you can simply re-run git-annex init
+    to install them.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Git/Hook.hs b/Git/Hook.hs
index 411a52ea4..9fcc0c66d 100644
--- a/Git/Hook.hs
+++ b/Git/Hook.hs
@@ -31,7 +31,18 @@ hookFile :: Hook -> Repo -> FilePath
 hookFile h r = localGitDir r </> "hooks" </> hookName h
 
 {- Writes a hook. Returns False if the hook already exists with a different
- - content. Upgrades old scripts. -}
+ - content. Upgrades old scripts.
+ -
+ - This can install hooks on both filesystem like FAT that do not support
+ - execute bits, and on Windows.
+ -
+ - If the filesystem does not support execute bits, it's typically mounted
+ - such that all files have the execute bit set. So just write the hook
+ - and ignore failure to make it executable.
+ -
+ - On Windows, git will run hooks that are not executable. The hook
+ - is run with a bundled bash, so should start with #!/bin/sh
+ -}
 hookWrite :: Hook -> Repo -> IO Bool
 hookWrite h r = ifM (doesFileExist f)
 	( expectedContent h r >>= \case
@@ -45,7 +56,7 @@ hookWrite h r = ifM (doesFileExist f)
 	go = do
 		viaTmp writeFile f (hookScript h)
 		p <- getPermissions f
-		setPermissions f $ p {executable = True}
+		void $ tryIO $ setPermissions f $ p {executable = True}
 		return True
 
 {- Removes a hook. Returns False if the hook contained something else, and
diff --git a/doc/bugs/windows_fails_import_export_tests.mdwn b/doc/bugs/windows_fails_import_export_tests.mdwn
index 51b1ef233..f502f9c96 100644
--- a/doc/bugs/windows_fails_import_export_tests.mdwn
+++ b/doc/bugs/windows_fails_import_export_tests.mdwn
@@ -1,27 +1,30 @@
-Two test failures on windows in the import/export tests. The tests fail on
-a v7 adjusted unlocked branch, but pass a direct mode. It may be that
-there's a problem with the tests outside of windows on an adjusted branch.
+Windows test suite fails the import/export tests.
 
-The first test fails to export all annexed files to a directory special
-remote.
+It imports a file, but the worktree file remains a unlocked pointer
+file. So the test fails. Running `git annex smudge--update` fixed the
+file content. 
 
-	export foo sha1foo failed
+Reproduced outside the test suite, and tried with GIT_TRACE=1.
+When `git-annex merge remote/master``runs git merge, it does then smudge
+--clean the imported files. But smudge --update does not get run. The
+post-merge hook should run it.
 
-No indication of why it failed.
+Ahh -- on windows, hooks are not written, because the code skips that
+for a crippled filesystem, assuming it has no execute bit.
 
-> Update: Now it shows the problem, which is that the exported file is
-> locked so statting it fails. --[[Joey]]
+So, this is both a problem on windows and on crippled filesystems.
+The user needs to run smudge --update themselves, or maybe git-annex
+can do it sometimes. Eg, `git annex merge` (and sync) could certianly
+smudge --update when on a crippled filesystem. And that would be
+enough to fix the test suite.
 
-The second test fails in an import. It gets as far as updating foo/master,
-but then when it tries to merge that branch, there's a merge conflict.
-That merge conflict seems very likely due to being on an adjusted branch;
-foo/master will have the non-adjusted version of the file and merging it
-into a branch where it's been adjusted does sound like there could be a
-legitimate merge conflict.
+But if a user is on a crippled filesystem with an adjusted branch, and
+they do some other operation that would be covered by post-merge or
+post-checkout hook, they will be surprised to find unpopulated pointer
+files in the working tree.
 
-If so, note that the git-annex-import man page suggests doing just such a
-merge, so perhaps the docs will need to be updated, if some git-annex
-command is instead used to do the merge. --[[Joey]]
-
-> Probably down to only one test failure now after some fixes. Have not
-> checked. --[[Joey]]
+I think this can be avoided. On eg fat on linux, all files are executable,
+so the hook can be installed and will work. On Windows, a hook can start
+with #!/bin/sh and not be executable, and will be run by the bash bundled
+with git for windows.
+--[[Joey]]

Added a comment
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_2_a61ed5b8f438caf0b8c7a53e08e1986a._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_2_a61ed5b8f438caf0b8c7a53e08e1986a._comment
new file mode 100644
index 000000000..1ccfc9a36
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_2_a61ed5b8f438caf0b8c7a53e08e1986a._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 2"
+ date="2019-08-13T18:15:36Z"
+ content="""
+and git-annex cannot rely on the check that size of the receiving file has reached the target size?
+"""]]

comment
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_1_ec7aa500a826beb813bc5313af9aa983._comment b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_1_ec7aa500a826beb813bc5313af9aa983._comment
new file mode 100644
index 000000000..4d3cd495e
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure/comment_1_ec7aa500a826beb813bc5313af9aa983._comment
@@ -0,0 +1,24 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2019-08-13T17:28:15Z"
+ content="""
+This is the same problem I tried to deal with in 
+[[!commit f27c5db5c566bdc0baae256b67df04a50027679f]].
+Apparently not fully
+
+Or at least the double run of rsync with no indication
+why it thought the first one failed appears to be the same.
+And IIRC I saw that sometimes without the permissions error and it still
+failed.
+
+I was having to run git-annex test in a loop for an hour or so to reproduce
+it.
+
+So, for some reason git-annex thinks the rsync failed, although it got to
+100%. If that happens once, it retries automatically. The second time it
+thinks rsync has failed, it sees the file didn't get any larger,
+and so gives up. That makes sense, but I don't know how rsync would get 
+to 100% and then apparently exit nonzero, without displaying any error
+message.
+"""]]

close handle so windows can stat the file
windows cannot stat a file that another process has open, which caused
this to crash with an exception
diff --git a/Remote/Directory.hs b/Remote/Directory.hs
index b6ef6be96..868cad1db 100644
--- a/Remote/Directory.hs
+++ b/Remote/Directory.hs
@@ -404,6 +404,7 @@ storeExportWithContentIdentifierM dir src _k loc overwritablecids p =
 		withTmpFileIn destdir template $ \tmpf tmph -> do
 			liftIO $ withMeteredFile src p (L.hPut tmph)
 			liftIO $ hFlush tmph
+			liftIO $ hClose tmph
 			liftIO (getFileStatus tmpf) >>= liftIO . mkContentIdentifier tmpf >>= \case
 				Nothing -> 
 					return $ Left "unable to generate content identifier"
diff --git a/doc/bugs/windows_fails_import_export_tests.mdwn b/doc/bugs/windows_fails_import_export_tests.mdwn
index c182b47ae..51b1ef233 100644
--- a/doc/bugs/windows_fails_import_export_tests.mdwn
+++ b/doc/bugs/windows_fails_import_export_tests.mdwn
@@ -9,6 +9,9 @@ remote.
 
 No indication of why it failed.
 
+> Update: Now it shows the problem, which is that the exported file is
+> locked so statting it fails. --[[Joey]]
+
 The second test fails in an import. It gets as far as updating foo/master,
 but then when it tries to merge that branch, there's a merge conflict.
 That merge conflict seems very likely due to being on an adjusted branch;

reply
diff --git a/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_1_d90a0f326840137872f551e54c2d2a53._comment b/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_1_d90a0f326840137872f551e54c2d2a53._comment
new file mode 100644
index 000000000..90271cec6
--- /dev/null
+++ b/doc/bugs/git-annex-sync_not_quite_idempotent__63__/comment_1_d90a0f326840137872f551e54c2d2a53._comment
@@ -0,0 +1,31 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2019-08-13T16:39:00Z"
+ content="""
+sync should be idempotent as long as the remote it's syncing with is not
+getting other changes made/pushed to it at the same time
+
+There are things in your transcript that are hard to understand:
+
+* The first sync does not have a "push origin" line, or any git output
+* indicating it pushed, but it made a commit and so it would normally
+  then try to push it.
+* The first sync does not have a "pull origin" line
+  at the beginning, but it does say 
+  "Your branch is up to date"
+  so it must have tried to pull from origin at the start,
+  which sync always does do.
+* Several other parts of the output appear to be
+  in a different order than could have occurred.
+  For example, the first thing sync does is "pull origin", but the
+  transcript has that as the last thing output by the first sync.
+* The highest bit of weirdness is that the first sync seems to pull
+  commit 1d808d3a08c..de7758ca784 from github, but the second sync
+  pushes 63fe6905f53..1d808d3a08c to github. Which kind of appears
+  as if the two syncs have been pasted in the opposite order than they were
+  run.
+
+This makes me suspect you didn't paste the output exactly as it appeared,
+and perhaps left part of it out.
+"""]]

Original report
diff --git a/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn b/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
new file mode 100644
index 000000000..d0407c048
--- /dev/null
+++ b/doc/bugs/fresh_build_for_neurodebian__58___test_failure.mdwn
@@ -0,0 +1,31 @@
+might be a flaky test/operation, happened while building in i386 buster environment:
+
+[[!format sh """
+neurodebian@smaug ..7.20190730+git103-g070fbd693-1~ndall+1 % grep -B20 -A1 FAIL git-annex_7.20190730+git103-g070fbd693-1~ndall+1_i386.build
+             20 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=0/1)
+(checksum...) (recording state in git...)
+ok
+(recording state in git...)
+OK (1.00s)
+    move (ssh remote):                                    move foo (from origin...) 
+(checksum...) ok                  
+(recording state in git...)
+move foo (to origin...) 
+ok                                
+(recording state in git...)
+OK (0.99s)
+    copy:                                                 copy foo (from origin...) 
+SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77
+             20 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=0/1)
+
+SHA256E-s20--e394a389d787383843decc5d3d99b6d184ffa5fddeec23b911f9ee7fc8b9ea77
+             20 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=0/1)
+failed
+copy: 1 failed
+FAIL (0.34s)
+      Test.hs:530:
+"""]]
+
+I have tried to rebuild (`debian/rules binary`) second time while in the same environment -- didn't succeed... but then I proceeded to build amd64 fine, and redid i386 build just fine
+
+[[!meta author=yoh]]

added bug report where git-annex-sync seems not idempotent
diff --git a/doc/bugs/git-annex-sync_not_quite_idempotent__63__.mdwn b/doc/bugs/git-annex-sync_not_quite_idempotent__63__.mdwn
new file mode 100644
index 000000000..4aea13c62
--- /dev/null
+++ b/doc/bugs/git-annex-sync_not_quite_idempotent__63__.mdwn
@@ -0,0 +1,90 @@
+### Please describe the problem.
+I had thought that, after running git-annex-sync in a repo, running it again should always do nothing (if no remote has changed).
+But I'm seeing an example where I have to run git-annex-sync twice for subsequent runs to do nothing.
+
+### What steps will reproduce the problem?
+See below.  The repo has one submodule, in the directory viral-ngs/ .
+
+### What version of git-annex are you using? On what operating system?
+
+[[!format sh """
+(master_env_v150_py36) 16:44  [viral-ngs-benchmarks] $ uname -a
+Linux ip-172-31-80-189.ec2.internal 4.14.133-113.112.amzn2.x86_64 #1 SMP Tue Jul 30 18:29:50 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
+(master_env_v150_py36) 16:46  [viral-ngs-benchmarks] $ git annex version
+git-annex version: 7.20190730-g1030771
+build flags: Assistant Webapp Pairing S3 WebDAV Inotify DBus DesktopNotify TorrentParser MagicMime Feeds Testsuite
+dependency versions: aws-0.21.1 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-sql\
+ite-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_2\
+24 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE\
+2B224E 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 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
+"""]]
+
+### 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
+(master_env_v150_py36) 16:44  [viral-ngs-benchmarks] $ git annex sync
+On branch is-import-rabies200
+Your branch is up to date with 'origin/is-import-rabies200'.
+
+
+It took 5.25 seconds to enumerate untracked files. 'status -uno'
+may speed it up, but you have to be careful not to forget to add
+new files yourself (see 'git help status').
+nothing to commit, working tree clean
+commit ok
+remote: Enumerating objects: 1, done.
+remote: Counting objects: 100% (1/1), done.
+remote: Total 1 (delta 0), reused 1 (delta 0), pack-reused 0
+Unpacking objects: 100% (1/1), done.
+From github.com:broadinstitute/viral-ngs-benchmarks
+   1d808d3a08c..de7758ca784  is-import-rabies200        -> origin/is-import-rabies200
+   1d808d3a08c..de7758ca784  synced/is-import-rabies200 -> origin/synced/is-import-rabies200
+Updating 1d808d3a08c..de7758ca784
+Fast-forward
+ viral-ngs | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Already up to date.
+pull origin ok
+(master_env_v150_py36) 16:44  [viral-ngs-benchmarks] $ git annex sync
+[is-import-rabies200 f3e0898cd33] git-annex in viral-ngs-benchmarks copy on /ilya
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+commit ok
+pull origin ok
+Enumerating objects: 3, done.
+Counting objects: 100% (3/3), done.
+Delta compression using up to 8 threads
+Compressing objects: 100% (2/2), done.
+Writing objects: 100% (2/2), 946 bytes | 946.00 KiB/s, done.
+Total 2 (delta 1), reused 0 (delta 0)
+remote: Resolving deltas: 100% (1/1), completed with 1 local object.
+To github.com:broadinstitute/viral-ngs-benchmarks.git
+   63fe6905f53..1d808d3a08c  is-import-rabies200 -> synced/is-import-rabies200
+push origin ok
+(master_env_v150_py36) 16:42  [viral-ngs-benchmarks] $ git annex sync
+On branch is-import-rabies200
+Your branch is up to date with 'origin/is-import-rabies200'.
+
+
+It took 5.36 seconds to enumerate untracked files. 'status -uno'
+may speed it up, but you have to be careful not to forget to add
+new files yourself (see 'git help status').
+nothing to commit, working tree clean
+commit ok
+pull origin ok
+
+
+# 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/test_suite_fails_on_windows/comment_3_e8ea2d2b744d1322ec8fa88af9a645c3._comment b/doc/bugs/test_suite_fails_on_windows/comment_3_e8ea2d2b744d1322ec8fa88af9a645c3._comment
new file mode 100644
index 000000000..f9719cf41
--- /dev/null
+++ b/doc/bugs/test_suite_fails_on_windows/comment_3_e8ea2d2b744d1322ec8fa88af9a645c3._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 3"
+ date="2019-08-12T20:15:01Z"
+ content="""
+Could there be some point release to facilitate Windows getting a version with not broken dependency?  We are still experiencing tests failures while installing/using [https://downloads.kitenet.net/git-annex/windows/current/git-annex-installer.exe](https://downloads.kitenet.net/git-annex/windows/current/git-annex-installer.exe) which reports git annex 
+7.20190709-g15a972dd3.  Ref: https://ci.appveyor.com/project/mih/datalad/builds/26646252/job/yvrb8hxqjo4ly6v1
+
+"""]]

Added a comment
diff --git a/doc/forum/Cannot_get_file_from_special_remote/comment_3_81a6054bc3b64f1325f4d85979f2b12a._comment b/doc/forum/Cannot_get_file_from_special_remote/comment_3_81a6054bc3b64f1325f4d85979f2b12a._comment
new file mode 100644
index 000000000..c067ce7b1
--- /dev/null
+++ b/doc/forum/Cannot_get_file_from_special_remote/comment_3_81a6054bc3b64f1325f4d85979f2b12a._comment
@@ -0,0 +1,24 @@
+[[!comment format=mdwn
+ username="Horus"
+ avatar="http://cdn.libravatar.org/avatar/8f0ee08b98ea5bba76c3fe112c08851c"
+ subject="comment 3"
+ date="2019-08-12T07:40:57Z"
+ content="""
+It gives me:
+
+```
+% git annex info StorageBox
+uuid: 00638e8a-ce29-4c41-b0df-e38bbbea303c
+description: [StorageBox]
+remote: StorageBox
+trust: semitrusted
+cost: 250.0
+type: webdav
+creds: embedded in git repository (gpg encrypted)
+url: https://xyz.your-storagebox.de/annex/Documents
+encryption: hybrid (to gpg keys: 4F4FB5E450C86B8F)
+chunking: 10 megabyteschunks
+remote annex keys: 9629
+remote annex size: 44.27 gigabytes
+```
+"""]]

diff --git a/doc/forum/Dropping_files_in_an_annex.thin_v7_repository.mdwn b/doc/forum/Dropping_files_in_an_annex.thin_v7_repository.mdwn
new file mode 100644
index 000000000..0ade7cb45
--- /dev/null
+++ b/doc/forum/Dropping_files_in_an_annex.thin_v7_repository.mdwn
@@ -0,0 +1,16 @@
+I think git-annex is an excellent project and could solve all my backup problems if I can just figure out how to use it properly!
+My primary usage is as a backup tool: I'm a commercial artist and animator so I have a large archive of projects and assets to manage. About two months ago I found out about git-annex and could see how it could help me create a distributed backup system and easily locate which external HDD the data is stored on.
+The tools I use don't play nicely with symlinks, so my local repository is upgraded to v7 and set to annex.thin.
+I had some issues with speed so I followed some steps [here](https://git-annex.branchable.com/tips/Repositories_with_large_number_of_files/) to get backups to complete in less than 30mins.
+
+Now a few months later, I've completed some projects and want to free up the space on my local HDD and just keep the backups - still being able to pull them down when I need to. I moved the files I want to drop into a directory '_archive' inside the repository. I ran 'git annex sync --content --to backupHDD01' at this point
+
+I tried running 'git annex drop _archive' but I get no output and the size of the directory stays the same.
+
+Then I tried locking every file in the directory and dropping it but again, no change.
+
+Looking through the directory, some of the files are broken symlinks (this is what I wanted) but most are still just hardlinks. Furthermore,'git annex whereis file.ext' only returns output on some of the files. 'git status' reports a clean working tree.
+
+Have I misinterpreted this whole annex.thin thing? Is there a better way to do what I want to do?
+
+Thanks! J.

devblog
diff --git a/doc/devblog/day_598__Windows_and_test_suite.mdwn b/doc/devblog/day_598__Windows_and_test_suite.mdwn
new file mode 100644
index 000000000..198b31ca1
--- /dev/null
+++ b/doc/devblog/day_598__Windows_and_test_suite.mdwn
@@ -0,0 +1,21 @@
+Spent several days fixing test suite failures on Windows. This started out
+really annoying; I had to chase back a "NUL" -- the string not the
+pointer! -- to a indirect dependency that needed an update to work with
+recent ghc on Windows.
+
+Then yesterday I fixed most of the other test suite failures on Windows.
+But, it became clear that the test suite was only testing adjusted unlocked
+branches on Windows, and was finding non-Windows-specific problems
+involving them. So, today I added a fifth pass to the test suite, so it
+will always test adjusted unlocked branches. And fixed all the problems
+with them that test suite turned up.
+
+It turned out there was no good way to use `git-annex import`
+with an adjusted branch. Merging the imported branch into an adjusted
+branch is likely to result in spurious merge conflicts, and the merged
+files don't get adjusted. The solution was adding a new way to merge
+a single branch in the same way that git-annex sync handles merges: 
+`git-annex merge remote/master`
+
+Sadly, I think there are still a couple of test failures on Windows.
+(Can't win em all..)

comment
diff --git a/doc/forum/Cannot_get_file_from_special_remote/comment_2_bbb832f022d23b1f020d07f3fe99577f._comment b/doc/forum/Cannot_get_file_from_special_remote/comment_2_bbb832f022d23b1f020d07f3fe99577f._comment
new file mode 100644
index 000000000..0fea4911c
--- /dev/null
+++ b/doc/forum/Cannot_get_file_from_special_remote/comment_2_bbb832f022d23b1f020d07f3fe99577f._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2019-08-09T19:38:36Z"
+ content="""
+What does `git annex info StorageBox` say about it?
+"""]]

make test_export_import work on adjusted branch
diff --git a/Test.hs b/Test.hs
index dd0972fd8..10165786b 100644
--- a/Test.hs
+++ b/Test.hs
@@ -36,7 +36,6 @@ import qualified Git.Types
 import qualified Git.Ref
 import qualified Git.LsTree
 import qualified Git.FilePath
-import qualified Git.Merge
 import qualified Annex.Locations
 #ifndef mingw32_HOST_OS
 import qualified Types.GitConfig
@@ -387,20 +386,6 @@ test_import = intmpclonerepo $ Utility.Tmp.Dir.withTmpDir "importtest" $ \import
 		let importf = subdir </> "f"
 		writecontent (importdir </> importf) (content importf)
 		return (importdir </> subdir, importdir </> importf, importf)
-	annexed_present_imported f = ifM (annexeval Config.crippledFileSystem)
-		( annexed_present_unlocked f
-		, ifM (adjustedUnlockedBranch <$> getTestMode) 
-			( annexed_present_unlocked f
-			, annexed_present_locked f
-			)
-		)
-	annexed_notpresent_imported f = ifM (annexeval Config.crippledFileSystem)
-		( annexed_notpresent_unlocked f
-		, ifM (adjustedUnlockedBranch <$> getTestMode)
-			( annexed_notpresent_unlocked f
-			, annexed_notpresent_locked f
-			)
-		)
 
 test_reinject :: Assertion
 test_reinject = intmpclonerepoInDirect $ do
@@ -1759,27 +1744,22 @@ test_export_import = intmpclonerepoInDirect $ do
 	git_annex "get" [] @? "get of files failed"
 	annexed_present annexedfile
 
-	-- When on an adjusted branch, this updates the master branch
-	-- to match it, which is necessary since the master branch is going
-	-- to be exported.
-	git_annex "sync" ["--no-pull", "--no-push"] @? "sync failed"
-
+	-- Nothing to commit, but this makes sure the master branch
+	-- is in sync with the adjusted branch, which it may not be
+	-- depending on how the repository was set up.
+	commitchanges
 	git_annex "export" ["master", "--to", "foo"] @? "export to dir failed"
 	dircontains annexedfile (content annexedfile)
 
 	writedir "import" (content "import")
 	git_annex "import" ["master", "--from", "foo"] @? "import from dir failed"
-	up <- Git.Merge.mergeUnrelatedHistoriesParam
-	let mergeps = [Param "merge", Param "foo/master", Param "-mmerge"] ++ maybeToList up
-	boolSystem "git" mergeps @? "git merge foo/master failed"
-	-- FIXME fails when in an adjusted unlocked branch because
-	-- it's imported locked
-	--annexed_present "import"
+	git_annex "merge" ["foo/master"] @? "git annex merge foo/master failed"
+	annexed_present_imported "import"
 
 	nukeFile "import"
 	writecontent "import" (content "newimport1")
 	git_annex "add" ["import"] @? "add of import failed"
-	boolSystem "git" [Param "commit", Param "-q", Param "-mchanged"] @? "git commit failed"
+	commitchanges
 	git_annex "export" ["master", "--to", "foo"] @? "export modified file to dir failed"
 	dircontains "import" (content "newimport1")
 
@@ -1788,7 +1768,7 @@ test_export_import = intmpclonerepoInDirect $ do
 	nukeFile "import"
 	writecontent "import" (content "newimport3")
 	git_annex "add" ["import"] @? "add of import failed"
-	boolSystem "git" [Param "commit", Param "-q", Param "-mchanged"] @? "git commit failed"
+	commitchanges
 	git_annex_shouldfail "export" ["master", "--to", "foo"] @? "export failed to fail in conflict"
 	dircontains "import" (content "newimport2")
 
@@ -1798,7 +1778,7 @@ test_export_import = intmpclonerepoInDirect $ do
 	nukeFile "import"
 	writecontent "import" (content "newimport3")
 	git_annex "add" ["import"] @? "add of import failed"
-	boolSystem "git" [Param "commit", Param "-q", Param "-mchanged"] @? "git commit failed"
+	commitchanges
 	git_annex "export" ["master", "--to", "foo"] @? "export failed after import conflict"
 	dircontains "import" (content "newimport3")
   where
@@ -1806,6 +1786,10 @@ test_export_import = intmpclonerepoInDirect $ do
 		((v==) <$> readFile ("dir" </> f))
 			@? ("did not find expected content of " ++ "dir" </> f)
 	writedir f = writecontent ("dir" </> f)
+	-- When on an adjusted branch, this updates the master branch
+	-- to match it, which is necessary since the master branch is going
+	-- to be exported.
+	commitchanges = git_annex "sync" ["--no-pull", "--no-push"] @? "sync failed"
 
 test_export_import_subdir :: Assertion
 test_export_import_subdir = intmpclonerepoInDirect $ do
diff --git a/Test/Framework.hs b/Test/Framework.hs
index 386974a95..b50538d60 100644
--- a/Test/Framework.hs
+++ b/Test/Framework.hs
@@ -400,6 +400,24 @@ annexed_present_locked f = ifM (annexeval Config.crippledFileSystem)
 annexed_present_unlocked :: FilePath -> Assertion
 annexed_present_unlocked = runchecks
 	[checkregularfile, checkcontent, checkwritable, inlocationlog]
+	
+annexed_present_imported :: FilePath -> Assertion
+annexed_present_imported f = ifM (annexeval Config.crippledFileSystem)
+	( annexed_present_unlocked f
+	, ifM (adjustedUnlockedBranch <$> getTestMode) 
+		( annexed_present_unlocked f
+		, annexed_present_locked f
+		)
+	)
+
+annexed_notpresent_imported :: FilePath -> Assertion
+annexed_notpresent_imported f = ifM (annexeval Config.crippledFileSystem)
+	( annexed_notpresent_unlocked f
+	, ifM (adjustedUnlockedBranch <$> getTestMode)
+		( annexed_notpresent_unlocked f
+		, annexed_notpresent_locked f
+		)
+	)
 
 unannexed :: FilePath -> Assertion
 unannexed = runchecks [checkregularfile, checkcontent, checkwritable]
diff --git a/doc/bugs/windows_export_tree_exports_empty_tree.mdwn b/doc/bugs/windows_export_tree_exports_empty_tree.mdwn
index 45af8f600..37523c71c 100644
--- a/doc/bugs/windows_export_tree_exports_empty_tree.mdwn
+++ b/doc/bugs/windows_export_tree_exports_empty_tree.mdwn
@@ -21,4 +21,5 @@ tests are likely to behave any differently there.
 
 On balance, I think that making the test case run a git-annex sync
 before exporting is good enough.
---[[Joey]]
+
+[[done]] --[[Joey]]
diff --git a/doc/bugs/windows_fails_import_export_tests.mdwn b/doc/bugs/windows_fails_import_export_tests.mdwn
index 1e8b39bbf..c182b47ae 100644
--- a/doc/bugs/windows_fails_import_export_tests.mdwn
+++ b/doc/bugs/windows_fails_import_export_tests.mdwn
@@ -19,3 +19,6 @@ legitimate merge conflict.
 If so, note that the git-annex-import man page suggests doing just such a
 merge, so perhaps the docs will need to be updated, if some git-annex
 command is instead used to do the merge. --[[Joey]]
+
+> Probably down to only one test failure now after some fixes. Have not
+> checked. --[[Joey]]

git-annex merge branch
* merge: When run with a branch parameter, merges from that branch.
This is especially useful when using an adjusted branch, because
it applies the same adjustment to the branch before merging it.
diff --git a/CHANGELOG b/CHANGELOG
index 4c65c5fba..24e9bde41 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -18,8 +18,11 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
   * init: When the repo is already initialized, and --version requests a
     different version, error out rather than silently not changing the
     version.
-  * Fix some test suite failures on Windows.
+  * merge: When run with a branch parameter, merges from that branch.
+    This is especially useful when using an adjusted branch, because
+    it applies the same adjustment to the branch before merging it.
   * test: Add pass using adjusted unlocked branch.
+  * Fix some test suite failures on Windows.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Command/Merge.hs b/Command/Merge.hs
index 8870e556b..ddeef3c68 100644
--- a/Command/Merge.hs
+++ b/Command/Merge.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2011, 2013 Joey Hess <id@joeyh.name>
+ - Copyright 2011-2019 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -9,27 +9,38 @@ module Command.Merge where
 
 import Command
 import qualified Annex.Branch
+import qualified Git
+import qualified Git.Branch
 import Annex.CurrentBranch
-import Command.Sync (prepMerge, mergeLocal, mergeConfig)
+import Command.Sync (prepMerge, mergeLocal, mergeConfig, merge)
 
 cmd :: Command
 cmd = command "merge" SectionMaintenance
-	"automatically merge changes from remotes"
-	paramNothing (withParams seek)
+	"merge changes from remotes"
+	(paramOptional paramRef) (withParams seek)
 
 seek :: CmdParams -> CommandSeek
-seek _ = do
-	commandAction mergeBranch
-	commandAction mergeSynced
+seek [] = do
+	prepMerge
+	commandAction mergeAnnexBranch
+	commandAction mergeSyncedBranch
+seek bs = do
+	prepMerge
+	forM_ bs (commandAction . mergeBranch . Git.Ref)
+seek _ = giveup ""
 
-mergeBranch :: CommandStart
-mergeBranch = starting "merge" (ActionItemOther (Just "git-annex")) $ do
+mergeAnnexBranch :: CommandStart
+mergeAnnexBranch = starting "merge" (ActionItemOther (Just "git-annex")) $ do
 	Annex.Branch.update
 	-- commit explicitly, in case no remote branches were merged
 	Annex.Branch.commit =<< Annex.Branch.commitMessage
 	next $ return True
 
-mergeSynced :: CommandStart
-mergeSynced = do
-	prepMerge
-	mergeLocal mergeConfig def =<< getCurrentBranch
+mergeSyncedBranch :: CommandStart
+mergeSyncedBranch = mergeLocal mergeConfig def =<< getCurrentBranch
+
+mergeBranch :: Git.Ref -> CommandStart
+mergeBranch r = starting "merge" (ActionItemOther (Just (Git.fromRef r))) $ do
+	currbranch <- getCurrentBranch
+	merge currbranch mergeConfig def Git.Branch.ManualCommit r
+	next $ return True
diff --git a/Test.hs b/Test.hs
index 620e81f40..dd0972fd8 100644
--- a/Test.hs
+++ b/Test.hs
@@ -1848,9 +1848,7 @@ test_export_import_subdir = intmpclonerepoInDirect $ do
 	
 	testimport = do
 		git_annex "import" ["master:"++subdir, "--from", "foo"] @? "import of subdir failed"
-		up <- Git.Merge.mergeUnrelatedHistoriesParam
-		let mergeps = [Param "merge", Param "foo/master", Param "-mmerge"] ++ maybeToList up
-		boolSystem "git" mergeps @? "git merge foo/master failed"
+		git_annex "merge" ["foo/master"] @? "git annex merge foo/master failed"
 
 		-- Make sure that import did not import the file to the top
 		-- of the repo.
diff --git a/doc/git-annex-adjust.mdwn b/doc/git-annex-adjust.mdwn
index 027d14a4f..c03a6e43b 100644
--- a/doc/git-annex-adjust.mdwn
+++ b/doc/git-annex-adjust.mdwn
@@ -24,6 +24,11 @@ To propagate commits from the adjusted branch back to the original branch,
 and to other repositories, as well as to merge in changes from other
 repositories, run `git annex sync`.
 
+When in an adjusted branch, using `git merge otherbranch` is often not
+ideal, because merging a non-adjusted branch may lead to unncessary
+merge conflicts, or add files in non-adjusted form. To avoid those
+problems, use `git annex merge otherbranch`.
+
 Re-running this command with the same options
 while inside the adjusted branch will update the adjusted branch
 as necessary (eg for `--hide-missing`), and will also propagate commits
diff --git a/doc/git-annex-import.mdwn b/doc/git-annex-import.mdwn
index a89986f01..89a30e82c 100644
--- a/doc/git-annex-import.mdwn
+++ b/doc/git-annex-import.mdwn
@@ -35,17 +35,23 @@ kinds of special remotes will let you configure them this way.
 To import from a special remote, you must specify the name of a branch.
 A corresponding remote tracking branch will be updated by `git annex
 import`. After that point, it's the same as if you had run a `git fetch`
-from a regular git remote; you can `git merge` the changes into your
+from a regular git remote; you can merge the changes into your
 currently checked out branch.
 
 For example:
 
 	git annex import master --from myremote
-	git merge myremote/master
+	git annex merge myremote/master
 
-Note that you may need to pass `--allow-unrelated-histories` the first time
-you `git merge` from an import. Think of this as the remote being a
-separate git repository with its own files. If you first
+You could just as well use `git merge myremote/master` as the second step,
+but using `git-annex merge` avoids a couple of gotchas. When using adjusted
+branches, it adjusts the branch before merging from it. And it avoids
+the merge failing on the first merge from an import due to unrelated
+histories.
+
+If you do use `git merge`, you can pass `--allow-unrelated-histories` the
+first time you `git merge` from an import. Think of this as the remote
+being a separate git repository with its own files. If you first
 `git annex export` files to a remote, and then `git annex import` from it,
 you won't need that option.
 
diff --git a/doc/git-annex-merge.mdwn b/doc/git-annex-merge.mdwn
index bb204d725..a8324ba33 100644
--- a/doc/git-annex-merge.mdwn
+++ b/doc/git-annex-merge.mdwn
@@ -1,16 +1,21 @@
 # NAME
 
-git-annex merge - automatically merge changes from remotes
+git-annex merge - merge changes from remotes
 
 # SYNOPSIS
 
-git annex merge
+git annex merge [branch]
 
 # DESCRIPTION
 
-This performs the same merging (and merge conflict resolution)
-that is done by the sync command, but without pushing or pulling any
-data.
+When run without any parameters, this performs the same merging (and merge
+conflict resolution) that is done by the sync command, but without pushing
+or pulling any data.
+
+When a branch to merge is specified, this merges it, using the same merge
+conflict resolution as the sync command. This is especially useful on
+an adjusted branch, because it applies the same adjustment to the
+branch before merging it.
 
 When annex.resolvemerge is set to false, merge conflict resolution
 will not be done.
@@ -21,6 +26,8 @@ will not be done.
 
 [[git-annex-sync]](1)
 
+[[git-annex-adjust]](1)
+
 # AUTHOR
 
 Joey Hess <id@joeyh.name>
diff --git a/doc/tips/android_sync_with_adb.mdwn b/doc/tips/android_sync_with_adb.mdwn
index c6b3f0f0f..2efab4f62 100644
--- a/doc/tips/android_sync_with_adb.mdwn
+++ b/doc/tips/android_sync_with_adb.mdwn
@@ -57,7 +57,7 @@ for more details, and bear in mind that you can also use commands like
 these to only import from or export to the android device:
 
 	git annex import master:android --from android
-	git merge android/master
+	git annex merge android/master
 	git annex export master:android --to android
 
 ## sample workflows

Added a comment
diff --git a/doc/forum/Cannot_get_file_from_special_remote/comment_1_7fd5cebf26042ff0de30746bf8a6adcf._comment b/doc/forum/Cannot_get_file_from_special_remote/comment_1_7fd5cebf26042ff0de30746bf8a6adcf._comment
new file mode 100644
index 000000000..ba19add12
--- /dev/null
+++ b/doc/forum/Cannot_get_file_from_special_remote/comment_1_7fd5cebf26042ff0de30746bf8a6adcf._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Horus"
+ avatar="http://cdn.libravatar.org/avatar/8f0ee08b98ea5bba76c3fe112c08851c"
+ subject="comment 1"
+ date="2019-08-09T07:51:07Z"
+ content="""
+I have fixed doing an fsck on that special remote and re-uploading the files. Still, I am puzzled how that could have happened...
+"""]]

Added a comment: HOWTO
diff --git a/doc/forum/fatal_-_corrupt_loose_object/comment_1_7b0da4185861fd5ff2a7345410678f82._comment b/doc/forum/fatal_-_corrupt_loose_object/comment_1_7b0da4185861fd5ff2a7345410678f82._comment
new file mode 100644
index 000000000..c1cd00f0a
--- /dev/null
+++ b/doc/forum/fatal_-_corrupt_loose_object/comment_1_7b0da4185861fd5ff2a7345410678f82._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="Lukey"
+ avatar="http://cdn.libravatar.org/avatar/c7c08e2efd29c692cc017c4a4ca3406b"
+ subject="HOWTO"
+ date="2019-08-08T20:21:10Z"
+ content="""
+Hi,
+I think this is what you are looking for: 
+http://git-annex.branchable.com/tips/what_to_do_when_a_repository_is_corrupted/
+"""]]

bug report
diff --git a/doc/bugs/windows_fails_import_export_tests.mdwn b/doc/bugs/windows_fails_import_export_tests.mdwn
new file mode 100644
index 000000000..1e8b39bbf
--- /dev/null
+++ b/doc/bugs/windows_fails_import_export_tests.mdwn
@@ -0,0 +1,21 @@
+Two test failures on windows in the import/export tests. The tests fail on
+a v7 adjusted unlocked branch, but pass a direct mode. It may be that
+there's a problem with the tests outside of windows on an adjusted branch.
+
+The first test fails to export all annexed files to a directory special
+remote.
+
+	export foo sha1foo failed
+
+No indication of why it failed.
+
+The second test fails in an import. It gets as far as updating foo/master,
+but then when it tries to merge that branch, there's a merge conflict.
+That merge conflict seems very likely due to being on an adjusted branch;
+foo/master will have the non-adjusted version of the file and merging it
+into a branch where it's been adjusted does sound like there could be a
+legitimate merge conflict.
+
+If so, note that the git-annex-import man page suggests doing just such a
+merge, so perhaps the docs will need to be updated, if some git-annex
+command is instead used to do the merge. --[[Joey]]

use separate main repo dir for each test suite pass
This way a failure to clean up the main repo dir from a previous pass
can't result in reusing that repo, which won't be configured right for the
current pass.
diff --git a/CHANGELOG b/CHANGELOG
index 40a36e7e6..33cd01c63 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -18,6 +18,7 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
   * init: When the repo is already initialized, and --version requests a
     different version, error out rather than silently not changing the
     version.
+  * Fix some test suite failures on Windows.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Test/Framework.hs b/Test/Framework.hs
index f1e90a8f3..4014409b9 100644
--- a/Test/Framework.hs
+++ b/Test/Framework.hs
@@ -102,7 +102,9 @@ innewrepo :: Assertion -> Assertion
 innewrepo a = withgitrepo $ \r -> indir r a
 
 inmainrepo :: Assertion -> Assertion
-inmainrepo = indir mainrepodir
+inmainrepo a = do
+	d <- mainrepodir
+	indir d a
 
 with_ssh_origin :: (Assertion -> Assertion) -> (Assertion -> Assertion)
 with_ssh_origin cloner a = cloner $ do
@@ -151,7 +153,8 @@ withtmpclonerepo = withtmpclonerepo' newCloneRepoConfig
 withtmpclonerepo' :: CloneRepoConfig -> (FilePath -> Assertion) -> Assertion
 withtmpclonerepo' cfg a = do
 	dir <- tmprepodir
-	clone <- clonerepo mainrepodir dir cfg
+	maindir <- mainrepodir
+	clone <- clonerepo maindir dir cfg
 	r <- tryNonAsync (a clone)
 	case r of
 		Right () -> return ()
@@ -164,7 +167,9 @@ disconnectOrigin :: Assertion
 disconnectOrigin = boolSystem "git" [Param "remote", Param "rm", Param "origin"] @? "remote rm"
 
 withgitrepo :: (FilePath -> Assertion) -> Assertion
-withgitrepo = bracket (setuprepo mainrepodir) return
+withgitrepo a = do
+	maindir <- mainrepodir
+	bracket (setuprepo maindir) return a
 
 indir :: FilePath -> IO a -> IO a
 indir dir a = do
@@ -425,12 +430,13 @@ withTestMode testmode inittests = withResource prepare release . const
   where
 	prepare = do
 		setTestMode testmode
+		setmainrepodir =<< newmainrepodir
 		case tryIngredients [consoleTestReporter] mempty inittests of
 			Nothing -> error "No tests found!?"
 			Just act -> unlessM act $
 				error "init tests failed! cannot continue"
 		return ()
-	release _ = cleanup mainrepodir
+	release _ = noop
 
 setTestMode :: TestMode -> IO ()
 setTestMode testmode = do
@@ -456,7 +462,6 @@ setTestMode testmode = do
 		, ("GIT_ANNEX_USE_GIT_SSH", "1")
 		, ("TESTMODE", show testmode)
 		]
-
 runFakeSsh :: [String] -> IO ()
 runFakeSsh ("-n":ps) = runFakeSsh ps
 runFakeSsh (_host:cmd:[]) = do
@@ -481,8 +486,24 @@ changeToTmpDir t = do
 tmpdir :: String
 tmpdir = ".t"
 
-mainrepodir :: FilePath
-mainrepodir = tmpdir </> "repo"
+mainrepodir :: IO FilePath
+mainrepodir = Utility.Env.getEnvDefault "MAINREPODIR"
+	(giveup "MAINREPODIR not set")
+
+setmainrepodir :: FilePath -> IO ()
+setmainrepodir d = Utility.Env.Set.setEnv "MAINREPODIR" d True
+
+newmainrepodir :: IO FilePath
+newmainrepodir = go (0 :: Int)
+  where
+	go n = do
+		let d = tmpdir </> "main" ++ show n
+		ifM (doesDirectoryExist d)
+			( go $ n + 1
+			, do
+				createDirectory d
+				return d
+			)
 
 tmprepodir :: IO FilePath
 tmprepodir = go (0 :: Int)
diff --git a/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn b/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
index 452d645fb..599da46d5 100644
--- a/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
+++ b/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
@@ -2,16 +2,13 @@ For some reason the test suite on windows is failing to set up the direct
 mode repo; git-annex direct fails because the repo is a v7 repo in adjusted
 unlocked mode.
 
-It seems it's not running git-annex init with --version=5,
-or it does and it gets ignored.
-
 I have not managed to reproduce this outside of the test suite.
-I wonder if perhaps the environment variable that the test suite sets
-to communicate with itself is not working on Windows, which sometimes
-has gotchas around environment variables. --[[Joey]]
 
 Hmm, I reordered the direct mode tests to come first, and the failure went
-away. Think that .t/repo gets reused, and being already a v7 repo, git annex
-init --version=7 silently did not change it. (Made that error out.)
-So the test suite should use different paths for the base repo in each test
-pass.
+away. Think that .t/repo gets reused somehow, and being already a v7 repo, 
+git annex init --version=7 silently did not change it. (Now it will error
+out instead.)
+
+.t/repo is supposed to be deleted between each pass, but deleting
+directories on Windows is a fairly probabalistic venture. It would be
+better to use a different repo path for each pass. [[done]] --[[Joey]]

have init --version fail when repo is already initialized with other version
init: When the repo is already initialized, and --version requests a
different version, error out rather than silently not changing the version.
diff --git a/CHANGELOG b/CHANGELOG
index c26e0eca4..40a36e7e6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,9 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
     since it needs 64 bit git now.
   * Build with silently-1.2.5.1 on Windows; the old one used "NUL" which
     is not supported with recent versions of ghc.
+  * init: When the repo is already initialized, and --version requests a
+    different version, error out rather than silently not changing the
+    version.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/Command/Init.hs b/Command/Init.hs
index e8d80a353..db6cb14fb 100644
--- a/Command/Init.hs
+++ b/Command/Init.hs
@@ -51,6 +51,12 @@ start os = starting "init" (ActionItemOther (Just $ initDesc os)) $
 
 perform :: InitOptions -> CommandPerform
 perform os = do
+	case initVersion os of
+		Nothing -> noop
+		Just wantversion -> getVersion >>= \case
+			Just v | v /= wantversion ->
+				giveup $ "This repository is already a initialized with version " ++ show (fromRepoVersion v) ++ ", not changing to requested version."
+			_ -> noop
 	initialize
 		(if null (initDesc os) then Nothing else Just (initDesc os))
 		(initVersion os)
diff --git a/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn b/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
index d5c123105..452d645fb 100644
--- a/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
+++ b/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
@@ -9,3 +9,9 @@ I have not managed to reproduce this outside of the test suite.
 I wonder if perhaps the environment variable that the test suite sets
 to communicate with itself is not working on Windows, which sometimes
 has gotchas around environment variables. --[[Joey]]
+
+Hmm, I reordered the direct mode tests to come first, and the failure went
+away. Think that .t/repo gets reused, and being already a v7 repo, git annex
+init --version=7 silently did not change it. (Made that error out.)
+So the test suite should use different paths for the base repo in each test
+pass.

bug
diff --git a/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn b/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
new file mode 100644
index 000000000..d5c123105
--- /dev/null
+++ b/doc/bugs/windows_test_suite_fails_to_init_direct_mode_repo.mdwn
@@ -0,0 +1,11 @@
+For some reason the test suite on windows is failing to set up the direct
+mode repo; git-annex direct fails because the repo is a v7 repo in adjusted
+unlocked mode.
+
+It seems it's not running git-annex init with --version=5,
+or it does and it gets ignored.
+
+I have not managed to reproduce this outside of the test suite.
+I wonder if perhaps the environment variable that the test suite sets
+to communicate with itself is not working on Windows, which sometimes
+has gotchas around environment variables. --[[Joey]]

work around adjusted unlocked branch problem in test suite
diff --git a/Test.hs b/Test.hs
index d9fdca995..8e16f50b2 100644
--- a/Test.hs
+++ b/Test.hs
@@ -1738,6 +1738,11 @@ test_export_import = intmpclonerepoInDirect $ do
 	git_annex "get" [] @? "get of files failed"
 	annexed_present annexedfile
 
+	-- When on an adjusted branch, this updates the master branch
+	-- to match it, which is necessary since the master branch is going
+	-- to be exported.
+	git_annex "sync" [] @? "sync failed"
+
 	git_annex "export" ["master", "--to", "foo"] @? "export to dir failed"
 	dircontains annexedfile (content annexedfile)
 
@@ -1793,6 +1798,11 @@ test_export_import_subdir = intmpclonerepoInDirect $ do
 		@? "git mv failed"
 	boolSystem "git" [Param "commit", Param "-m", Param "moved"]
 		@? "git commit failed"
+	
+	-- When on an adjusted branch, this updates the master branch
+	-- to match it, which is necessary since the master branch is going
+	-- to be exported.
+	git_annex "sync" [] @? "sync failed"
 
 	-- Run three times because there was a bug that took a couple
 	-- of runs to lead to the wrong tree being written to the remote
diff --git a/doc/bugs/windows_export_tree_exports_empty_tree.mdwn b/doc/bugs/windows_export_tree_exports_empty_tree.mdwn
new file mode 100644
index 000000000..45af8f600
--- /dev/null
+++ b/doc/bugs/windows_export_tree_exports_empty_tree.mdwn
@@ -0,0 +1,24 @@
+The test suite's `test_export_import` fails on Windows.
+It seems that exporting a tree that contains annexed files
+somehow ends up exporting an empty tree.
+
+The test is running in an adjusted unlocked branch. But it exports
+the master branch. The master branch indeed contains an empty tree.
+
+The origin repo is also using an adjusted unlocked branch. Some changes
+have been committed there, but not synced back to the master branch.
+
+On clone from that, git-annex sets up an adjusted unlocked branch,
+and it merges origin's adjusted unlocked branch in. So the annexed files
+are present in that branch, but still not in master.
+
+This is not really a windows-specific problem. Only on windows or perhaps
+on a crippled FS does the test suite actually test opeation in an unlocked
+adjusted branch, because it enters that mode only on demand. Arguably
+the test suite should run all the tests separately on an adjusted branch,
+but that would add a lot of extra time to the test suite and very few
+tests are likely to behave any differently there.
+
+On balance, I think that making the test case run a git-annex sync
+before exporting is good enough.
+--[[Joey]]

removed
diff --git a/doc/install/comment_11_e5ecbe8bc745f6dbae5e81e246a49ba1._comment b/doc/install/comment_11_e5ecbe8bc745f6dbae5e81e246a49ba1._comment
deleted file mode 100644
index fe8af5211..000000000
--- a/doc/install/comment_11_e5ecbe8bc745f6dbae5e81e246a49ba1._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="Ilya_Shlyakhter"
- avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
- subject="Git for Windows installation -- support for symlinks"
- date="2019-08-08T15:04:39Z"
- content="""
-The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
-"""]]

removed
diff --git a/doc/install/comment_10_7d113fc83a7e2bda8c13be335f36201b._comment b/doc/install/comment_10_7d113fc83a7e2bda8c13be335f36201b._comment
deleted file mode 100644
index 6040616ce..000000000
--- a/doc/install/comment_10_7d113fc83a7e2bda8c13be335f36201b._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="Ilya_Shlyakhter"
- avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
- subject="Git for Windows installation -- support for symlinks"
- date="2019-08-08T15:04:32Z"
- content="""
-The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
-"""]]

removed
diff --git a/doc/install/comment_9_6ea4279bacd2aca026329930c570fbe5._comment b/doc/install/comment_9_6ea4279bacd2aca026329930c570fbe5._comment
deleted file mode 100644
index 4b1bf9a0d..000000000
--- a/doc/install/comment_9_6ea4279bacd2aca026329930c570fbe5._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="Ilya_Shlyakhter"
- avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
- subject="Git for Windows installation -- support for symlinks"
- date="2019-08-08T15:04:24Z"
- content="""
-The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
-"""]]

Added a comment: Git for Windows installation -- support for symlinks
diff --git a/doc/install/comment_11_e5ecbe8bc745f6dbae5e81e246a49ba1._comment b/doc/install/comment_11_e5ecbe8bc745f6dbae5e81e246a49ba1._comment
new file mode 100644
index 000000000..fe8af5211
--- /dev/null
+++ b/doc/install/comment_11_e5ecbe8bc745f6dbae5e81e246a49ba1._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="Git for Windows installation -- support for symlinks"
+ date="2019-08-08T15:04:39Z"
+ content="""
+The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
+"""]]

Added a comment: Git for Windows installation -- support for symlinks
diff --git a/doc/install/comment_10_7d113fc83a7e2bda8c13be335f36201b._comment b/doc/install/comment_10_7d113fc83a7e2bda8c13be335f36201b._comment
new file mode 100644
index 000000000..6040616ce
--- /dev/null
+++ b/doc/install/comment_10_7d113fc83a7e2bda8c13be335f36201b._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="Git for Windows installation -- support for symlinks"
+ date="2019-08-08T15:04:32Z"
+ content="""
+The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
+"""]]

Added a comment: Git for Windows installation -- support for symlinks
diff --git a/doc/install/comment_9_6ea4279bacd2aca026329930c570fbe5._comment b/doc/install/comment_9_6ea4279bacd2aca026329930c570fbe5._comment
new file mode 100644
index 000000000..4b1bf9a0d
--- /dev/null
+++ b/doc/install/comment_9_6ea4279bacd2aca026329930c570fbe5._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="Git for Windows installation -- support for symlinks"
+ date="2019-08-08T15:04:24Z"
+ content="""
+The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
+"""]]

Added a comment: Git for Windows installation -- support for symlinks
diff --git a/doc/install/comment_8_768498659909c37044f2b4dd08bacda3._comment b/doc/install/comment_8_768498659909c37044f2b4dd08bacda3._comment
new file mode 100644
index 000000000..73e75dee5
--- /dev/null
+++ b/doc/install/comment_8_768498659909c37044f2b4dd08bacda3._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="Git for Windows installation -- support for symlinks"
+ date="2019-08-08T15:04:07Z"
+ content="""
+The Git for Windows installer has a setting to turn on support for symlinks, which is not the default.  It says something about symlinks requiring special permissions.  What setting should be used with git-annex?
+"""]]

fixed
diff --git a/doc/bugs/test_suite_fails_on_windows.mdwn b/doc/bugs/test_suite_fails_on_windows.mdwn
index b6cb9a0bd..8de92cf7c 100644
--- a/doc/bugs/test_suite_fails_on_windows.mdwn
+++ b/doc/bugs/test_suite_fails_on_windows.mdwn
@@ -685,3 +685,4 @@ git-annex: .t\repo\.git\objects\f9\b6e5e36be4911f475c5a96dbc0c2c5d4b256af: remov
 ### 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)
 
 
+> Confirmed that my silently fix fixed it, [[done]] --[[Joey]]

Build with silently-1.2.5.1 on Windows; the old one used "NUL" which is not supported with recent versions of ghc.
diff --git a/CHANGELOG b/CHANGELOG
index 756459998..c26e0eca4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,8 @@ git-annex (7.20190731) UNRELEASED; urgency=medium
     newlines.
   * Windows installer: Always install to 64 bit program files directory,
     since it needs 64 bit git now.
+  * Build with silently-1.2.5.1 on Windows; the old one used "NUL" which
+    is not supported with recent versions of ghc.
 
  -- Joey Hess <id@joeyh.name>  Thu, 01 Aug 2019 00:11:56 -0400
 
diff --git a/doc/bugs/test_suite_fails_on_windows/comment_2_4e8d054e01ec9678d90e90f15b1da8a6._comment b/doc/bugs/test_suite_fails_on_windows/comment_2_4e8d054e01ec9678d90e90f15b1da8a6._comment
new file mode 100644
index 000000000..1bf02ba58
--- /dev/null
+++ b/doc/bugs/test_suite_fails_on_windows/comment_2_4e8d054e01ec9678d90e90f15b1da8a6._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2019-08-07T21:20:58Z"
+ content="""
+Tracked it back to runSqliteInfo. Both that and runSqlite use NUL
+somewhere.
+
+So the bug is in persistent-sqlite, or one of its dependencies.
+
+Aha! silently-1.2.5, used by persistent in runMigrationSilent,
+and it's already been fixed in a point release. I've bumped the dependency,
+hopefully that will fix this.
+"""]]
diff --git a/git-annex.cabal b/git-annex.cabal
index a2e574306..996403df0 100644
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -393,7 +393,8 @@ Executable git-annex
       Win32 (>= 2.6.1.0),
       unix-compat (>= 0.5),
       setenv,
-      process (>= 1.6.2.0)
+      silently (>= 1.2.5.1)
+      process (>= 1.6.2.0),
   else
     Build-Depends: unix (>= 2.7.2)
 
diff --git a/stack.yaml b/stack.yaml
index cedf2d9c7..d97bf2f26 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -23,6 +23,7 @@ extra-deps:
 - torrent-10000.1.1
 - sandi-0.5
 - http-client-0.5.14
+- silently-1.2.5.1
 explicit-setup-deps:
   git-annex: true
 resolver: lts-13.29

comment
diff --git a/doc/bugs/test_suite_fails_on_windows/comment_1_1fcc64cfab4a9d9d215c85788db0e1db._comment b/doc/bugs/test_suite_fails_on_windows/comment_1_1fcc64cfab4a9d9d215c85788db0e1db._comment
new file mode 100644
index 000000000..169d47c2d
--- /dev/null
+++ b/doc/bugs/test_suite_fails_on_windows/comment_1_1fcc64cfab4a9d9d215c85788db0e1db._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2019-08-07T17:14:22Z"
+ content="""
+Just running "git-annex add" on a file on windows is enough to reproduce
+the bug.
+
+This must be related to ghc 8.6.1's change to Windows paths that made "NUL"
+not work, but git-annex has been using the device namespace workaround for
+nearly a year now.
+
+Presumably the recent upgrade of the windows autobuilder's toolchain
+exposed the problem. Maybe something had a reversion?
+
+In ghci 8.6.5, this works fine, no error:
+
+	withFile "\\\\.\\NUL" ReadMode (\h -> print "opened NUL ok")
+
+Need to try ghci Utility/Process.hs on windows and see if running
+`withNullHandle (const noop)` works.
+"""]]

diff --git a/doc/forum/fatal_-_corrupt_loose_object.mdwn b/doc/forum/fatal_-_corrupt_loose_object.mdwn
new file mode 100644
index 000000000..608ed22ba
--- /dev/null
+++ b/doc/forum/fatal_-_corrupt_loose_object.mdwn
@@ -0,0 +1,14 @@
+After an unobserved problem a few days ago, one of my git annex repositories has become corrupt
+
+    [frederik@maui Documents]$ git status
+    error: object file .git/objects/e2/98e448aa2473a52c0abaef99aed1bf1a5fe94e is empty
+    error: object file .git/objects/e2/98e448aa2473a52c0abaef99aed1bf1a5fe94e is empty
+    error: object file .git/objects/e2/98e448aa2473a52c0abaef99aed1bf1a5fe94e is empty
+    fatal: loose object e298e448aa2473a52c0abaef99aed1bf1a5fe94e (stored in .git/objects/e2/98e448aa2473a52c0abaef99aed1bf1a5fe94e) is corrupt
+
+Most advice I can find relating to this error centers around re-cloning the repository - as does [this wiki's disaster recovery page](https://git-annex.branchable.com/design/assistant/disaster_recovery/)
+
+I have 2 remotes that should have most if not all of the content of the local one, but they're on the internet and downloading all content will take a while. Are there any steps I can safely take before having to re-clone? I was unable to work out from the above page what the best steps in this particular situation are. `git fsck` also stops with the same fatal error as above.
+
+
+

diff --git a/doc/forum/Cannot_get_file_from_special_remote.mdwn b/doc/forum/Cannot_get_file_from_special_remote.mdwn
new file mode 100644
index 000000000..eb1b6c74e
--- /dev/null
+++ b/doc/forum/Cannot_get_file_from_special_remote.mdwn
@@ -0,0 +1,62 @@
+Hello,
+
+I have an enabled special remote called StorageBox:
+
+```
+% git annex whereis esp\ 07.odt             
+whereis esp 07.odt (3 copies) 
+        00638e8a-ce29-4c41-b0df-e38bbbea303c -- [StorageBox]
+        2f41eb74-5f33-4737-bb6b-1cd31dd67ee5 -- External
+        8aca09c1-30bb-4c2a-9ea4-94a7096fc8b0 -- Horus [horus]
+ok
+```
+
+but getting the file fails:
+
+```
+% git annex get esp\ 07.odt --from StorageBox
+get esp 07.odt (from StorageBox...) 
+failed
+git-annex: get: 1 failed
+```
+
+with `--debug`
+
+```
+% git annex --debug get esp\ 07.odt --from StorageBox
+[2019-08-07 10:19:16.795808079] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","show-ref","git-annex"]
+[2019-08-07 10:19:16.798356234] process done ExitSuccess
+[2019-08-07 10:19:16.798450913] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","show-ref","--hash","refs/heads/git-annex"]
+[2019-08-07 10:19:16.800783647] process done ExitSuccess
+[2019-08-07 10:19:16.80113337] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","log","refs/heads/git-annex..a41476d65829e7e2bc2c7abb8bc5dbc54690bce2","--pretty=%H","-n1"]
+[2019-08-07 10:19:16.803608041] process done ExitSuccess
+[2019-08-07 10:19:16.803697638] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","log","refs/heads/git-annex..156c3e15a2aad0b1207c1574609044170312ea9f","--pretty=%H","-n1"]
+[2019-08-07 10:19:16.806435853] process done ExitSuccess
+[2019-08-07 10:19:16.806527203] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","log","refs/heads/git-annex..ea4446ee38012a32e58a041ccb538135c3e942be","--pretty=%H","-n1"]
+[2019-08-07 10:19:16.809451267] process done ExitSuccess
+[2019-08-07 10:19:16.809558251] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","log","refs/heads/git-annex..4f376a557a384044ef4b7ca481e9ca4c724cf13d","--pretty=%H","-n1"]
+[2019-08-07 10:19:16.811953178] process done ExitSuccess
+[2019-08-07 10:19:16.816776692] chat: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","cat-file","--batch"]
+[2019-08-07 10:19:16.817315416] chat: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","cat-file","--batch-check=%(objectname) %(objecttype) %(objectsize)"]
+[2019-08-07 10:19:16.821800692] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","symbolic-ref","-q","HEAD"]
+[2019-08-07 10:19:16.823817987] process done ExitSuccess
+[2019-08-07 10:19:16.823920732] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","show-ref","refs/heads/master"]
+[2019-08-07 10:19:16.826402914] process done ExitSuccess
+[2019-08-07 10:19:16.82657316] read: git ["--git-dir=../.git","--work-tree=..","--literal-pathspecs","ls-files","--cached","-z","--","esp 07.odt"]
+get esp 07.odt (from StorageBox...) [2019-08-07 10:19:16.835457997] chat: gpg ["--quiet","--trust-model","always","--decrypt"]
+[2019-08-07 10:19:16.983557153] process done ExitSuccess
+
+[2019-08-07 10:19:17.006493687] retrieve 065/2b5/GPGHMACSHA1--ae77770aef3b651d6fd0da47386891e23015809b/GPGHMACSHA1--ae77770aef3b651d6fd0da47386891e23015809b
+[2019-08-07 10:19:17.32316296] retrieve d8f/3a4/GPGHMACSHA1--ab824710fe31cc23b667dff462af11739d4e116d/GPGHMACSHA1--ab824710fe31cc23b667dff462af11739d4e116d
+failed
+[2019-08-07 10:19:17.338120828] process done ExitSuccess
+[2019-08-07 10:19:17.338792003] process done ExitSuccess
+git-annex: get: 1 failed
+```
+
+The testing when I did `enableremote` was successful.
+
+What can be the reason for that failure?
+
+Thanks,
+Florian

Added a comment: similar bug report
diff --git a/doc/bugs/parallel_copy_fails/comment_1_a8ffe32e04cbcbf9551e9d3a1ecf716d._comment b/doc/bugs/parallel_copy_fails/comment_1_a8ffe32e04cbcbf9551e9d3a1ecf716d._comment
new file mode 100644
index 000000000..33c3d8340
--- /dev/null
+++ b/doc/bugs/parallel_copy_fails/comment_1_a8ffe32e04cbcbf9551e9d3a1ecf716d._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="similar bug report"
+ date="2019-08-05T17:55:21Z"
+ content="""
+[[bugs/concurrent_git-annex-copy_to_s3_special_remote_fails]]
+"""]]

Added a comment: issues with concurrent copy
diff --git a/doc/bugs/concurrent_git-annex-copy_to_s3_special_remote_fails/comment_1_31242c64bc6d9760bca99687d4a5c1c8._comment b/doc/bugs/concurrent_git-annex-copy_to_s3_special_remote_fails/comment_1_31242c64bc6d9760bca99687d4a5c1c8._comment
new file mode 100644
index 000000000..e7a93d9aa
--- /dev/null
+++ b/doc/bugs/concurrent_git-annex-copy_to_s3_special_remote_fails/comment_1_31242c64bc6d9760bca99687d4a5c1c8._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Ilya_Shlyakhter"
+ avatar="http://cdn.libravatar.org/avatar/1647044369aa7747829c38b9dcc84df0"
+ subject="issues with concurrent copy"
+ date="2019-08-05T17:53:37Z"
+ content="""
+I've seen similar issues with concurrent copy: [[bugs/parallel_copy_fails]]
+"""]]

devblog
diff --git a/doc/devblog/day_597__git-lfs_support.mdwn b/doc/devblog/day_597__git-lfs_support.mdwn
new file mode 100644
index 000000000..9b9b13f2d
--- /dev/null
+++ b/doc/devblog/day_597__git-lfs_support.mdwn
@@ -0,0 +1,16 @@
+I've spent a week making git-annex be able to store files in a remote
+on a server using git-lfs.
+
+That included writing a haskell implementation of the git-lfs protocol.
+That could be split out of git-annex into a library if someone wants to use
+it for something else.
+
+Now [[git-lfs is now just another special remote|special_remotes/git-lfs]]
+as far as git-annex is concerned. Albeit one that it can't drop data from,
+because the git-lfs protocol does not have a way to delete an object.
+
+Once nice thing about git-annex's support for git-lfs is it can be used
+along with git-remote-gcrypt, and the result is a remote where both the
+annexed files and the git repo contents are both encrypted.
+
+See [[tips/storing_data_in_git-lfs]] for details.

close
diff --git a/doc/todo/LFS_API_support.mdwn b/doc/todo/LFS_API_support.mdwn
index 79bbf2ddc..8cb525e94 100644
--- a/doc/todo/LFS_API_support.mdwn
+++ b/doc/todo/LFS_API_support.mdwn
@@ -81,6 +81,8 @@ Thanks for your great work! :) -- [[anarcat]]
 
 > Started some initial work in the `git-lfs` branch. --[[Joey]]
 
+[[done]]! --[[Joey]]
+
 ---
 
 ## related ideas

support using gcrypt with git-lfs special remote
diff --git a/CHANGELOG b/CHANGELOG
index 2781a67ba..2aa6630d0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,10 @@
 git-annex (7.20190731) UNRELEASED; urgency=medium
 
+  * New git-lfs special remote, which can be used to store data on any git-lfs
+    server, including github, gitlab, and gogs.
+  * Support fully encrypting all data sent to a git-lfs special remote,
+    using a combination of gcrypt to encrypt the git data, and git-annex's
+    encryption of its data.
   * Use the same optimisation for --in=here as has always been
     used for --in=. rather than the slow code path that unncessarily
     queries the git-annex branch.
diff --git a/Remote/GCrypt.hs b/Remote/GCrypt.hs
index 83ab5c3b8..931a1491f 100644
--- a/Remote/GCrypt.hs
+++ b/Remote/GCrypt.hs
@@ -12,6 +12,7 @@ module Remote.GCrypt (
 	coreGCryptId,
 	setupRepo,
 	accessShellConfig,
+	setGcryptEncryption,
 ) where
 
 import qualified Data.Map as M
diff --git a/Remote/Git.hs b/Remote/Git.hs
index 6e9af5dd5..e7ed22404 100644
--- a/Remote/Git.hs
+++ b/Remote/Git.hs
@@ -144,8 +144,10 @@ configRead autoinit r = do
 
 gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
 gen r u c gc
-	| Git.GCrypt.isEncrypted r = Remote.GCrypt.chainGen r u c gc
+	-- Remote.GitLFS may be used with a repo that is also encrypted
+	-- with gcrypt so is checked first.
 	| remoteAnnexGitLFS gc = Remote.GitLFS.gen r u c gc
+	| Git.GCrypt.isEncrypted r = Remote.GCrypt.chainGen r u c gc
 	| otherwise = case repoP2PAddress r of
 		Nothing -> do
 			st <- mkState r u gc
diff --git a/Remote/GitLFS.hs b/Remote/GitLFS.hs
index 60b356761..4765d2fdd 100644
--- a/Remote/GitLFS.hs
+++ b/Remote/GitLFS.hs
@@ -16,12 +16,14 @@ import qualified Annex
 import qualified Git
 import qualified Git.Types as Git
 import qualified Git.Url
+import qualified Git.GCrypt
 import Config
 import Config.Cost
 import Remote.Helper.Special
 import Remote.Helper.ExportImport
 import Remote.Helper.Git
 import Remote.Helper.Http
+import qualified Remote.GCrypt
 import Annex.Ssh
 import Annex.UUID
 import Crypto
@@ -55,7 +57,14 @@ remote = RemoteType
 
 gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
 gen r u c gc = do
-	h <- liftIO $ newTVarIO $ LFSHandle Nothing Nothing r gc
+	-- If the repo uses gcrypt, get the underlaying repo without the
+	-- gcrypt url, to do LFS endpoint discovery on.
+	r' <- if Git.GCrypt.isEncrypted r
+		then do
+			g <- Annex.gitRepo
+			liftIO $ Git.GCrypt.encryptedRemote g r
+		else pure r
+	h <- liftIO $ newTVarIO $ LFSHandle Nothing Nothing r' gc
 	cst <- remoteCost gc expensiveRemoteCost
 	return $ Just $ specialRemote' specialcfg c
 		(simplyPrepare $ store u h)
@@ -107,36 +116,45 @@ mySetup :: SetupStage -> Maybe UUID -> Maybe CredPair -> RemoteConfig -> RemoteG
 mySetup _ mu _ c gc = do
 	u <- maybe (liftIO genUUID) return mu
 
-	let repo = fromMaybe (giveup "Specify url=") $
-		M.lookup "url" c
-	
-	when (isEncrypted c) $
-		unlessM (Annex.getState Annex.force) $
+	(c', _encsetup) <- encryptionSetup c gc
+	case (isEncrypted c', Git.GCrypt.urlPrefix `isPrefixOf` url) of
+		(False, False) -> noop
+		(True, True) -> Remote.GCrypt.setGcryptEncryption c' remotename
+		(True, False) -> unlessM (Annex.getState Annex.force) $
 			giveup $ unwords $
-				[ "You asked that encryption be enabled for"
-				, "this remote, but only the files that"
-				, "git-annex stores on it would be encrypted;"
+				[ "Encryption is enabled for this remote,"
+				, "but only the files that git-annex stores on"
+				, "it would be encrypted; "
 				, "anything that git push sends to it would"
-				, "not be encrypted. Even encryption=shared"
-				, "encryption keys will be stored on the"
-				, "remote for anyone who can access it to"
-				, "see."
+				, "not be encrypted. Recommend prefixing the"
+				, "url with \"gcrypt::\" to also encrypt"
+				, "git pushes."
+				, "(Use --force if you want to use this"
+				, "likely insecure configuration.)"
+				]
+		(False, True) -> unlessM (Annex.getState Annex.force) $
+			giveup $ unwords $
+				[ "You used a \"gcrypt::\" url for this remote,"
+				, "but encryption=none prevents git-annex"
+				, "from encrypting files it stores there."
 				, "(Use --force if you want to use this"
 				, "likely insecure configuration.)"
 				]
-	(c', _encsetup) <- encryptionSetup c gc
 
-	-- The repo is not stored in the remote log, because the same
+	-- The url is not stored in the remote log, because the same
 	-- git-lfs repo can be accessed using different urls by different
 	-- people (eg over ssh or http).
 	--
 	-- Instead, set up remote.name.url to point to the repo,
 	-- (so it's also usable by git as a non-special remote),
 	-- and set remote.name.git-lfs = true
-	let c'' = M.delete "repo" c'
+	let c'' = M.delete "url" c'
 	gitConfigSpecialRemote u c'' [("git-lfs", "true")]
-	setConfig (ConfigKey ("remote." ++ getRemoteName c ++ ".url")) repo
+	setConfig (ConfigKey ("remote." ++ getRemoteName c ++ ".url")) url
 	return (c'', u)
+  where
+	url = fromMaybe (giveup "Specify url=") (M.lookup "url" c)
+	remotename = fromJust (M.lookup "name" c)
 
 data LFSHandle = LFSHandle
 	{ downloadEndpoint :: Maybe LFS.Endpoint
diff --git a/doc/special_remotes/gcrypt.mdwn b/doc/special_remotes/gcrypt.mdwn
index 5807c9e5f..2842e4330 100644
--- a/doc/special_remotes/gcrypt.mdwn
+++ b/doc/special_remotes/gcrypt.mdwn
@@ -4,6 +4,12 @@ remote allows git-annex to also store its files in such repositories.
 Naturally, git-annex encrypts the files it stores too, so everything
 stored on the remote is encrypted.
 
+This special remote needs the server hosting the remote repository
+to either have git-annex-shell or rsync accessible via ssh. git-annex
+uses those to store its content in the remote. If the remote repository
+is instead hosted on a server using git-lfs, you can use the [[git-lfs]]
+special remote instead of this one; it also supports using gcrypt.
+
 See [[tips/fully_encrypted_git_repositories_with_gcrypt]] for some examples
 of using gcrypt.
 
@@ -35,11 +41,12 @@ shell access, and `rsync` must be installed. Those are the minimum
 requirements, but it's also recommended to install git-annex on the remote
 server, so that [[git-annex-shell]] can be used.
 
-While you can use git-remote-gcrypt with servers like github, git-annex
-can't store files on them. In such a case, you can just use
-git-remote-gcrypt directly.
+If you can't run `rsync` or `git-annex-shell` on the remote server,
+you can't use this special remote. Other options are the [[git-lfs]]
+special remote, which can also be combined with gcrypt, or 
+using git-remote-gcrypt to encrypt a remote that git-annex cannot use.
 
-If you use encryption=hybrid, you can add more gpg keys that can access
+If you use encryption=hybrid, you can later add more gpg keys that can access
 the files git-annex stored in the gcrypt repository. However, due to the
 way git-remote-gcrypt encrypts the git repository, you will need to somehow
 force it to re-push everything again, so that the encrypted repository can
diff --git a/doc/special_remotes/git-lfs.mdwn b/doc/special_remotes/git-lfs.mdwn
index ffb0e7411..e48a76cf4 100644
--- a/doc/special_remotes/git-lfs.mdwn
+++ b/doc/special_remotes/git-lfs.mdwn
@@ -23,8 +23,8 @@ the git-lfs special remote:
 
 * `keyid` - Specifies the gpg key to use for encryption of both the files
   git-annex stores in the repository, as well as to encrypt the git
-  repository itself. May be repeated when multiple participants
-  should have access to the repository.
+  repository itself when using gcrypt. May be repeated when
+  multiple participants should have access to the repository.
 
 ## efficiency note
 
@@ -41,15 +41,43 @@ store its SHA256 checksum in the git-annex branch.
 
 ## encryption notes
 
-The encryption= parameter only makes git-annex encrypt data it stores
-on the remote. `git push` can also be used with the remote
-(it is a git repository after all), and data pushed to it with
-git will *not* be encrypted.
+To encrypt a git-lfs repository, there are two separate things that
+have to be encrypted: the data git-annex stores there, and the content
+of the git repository itself. After all, a git-lfs remote is a git remote

(Diff truncated)
add encryption warning
diff --git a/Remote/GitLFS.hs b/Remote/GitLFS.hs
index bdacf5948..60b356761 100644
--- a/Remote/GitLFS.hs
+++ b/Remote/GitLFS.hs
@@ -12,6 +12,7 @@ import Types.Remote
 import Annex.Url
 import Types.Key
 import Types.Creds
+import qualified Annex
 import qualified Git
 import qualified Git.Types as Git
 import qualified Git.Url
@@ -108,11 +109,21 @@ mySetup _ mu _ c gc = do
 
 	let repo = fromMaybe (giveup "Specify url=") $
 		M.lookup "url" c
-	-- TODO: don't allow using encryption w/o the user indicating they
-	-- know it will only encrypt git-annex objects, not git pushes
-	-- TODO: don't allow using encryption=shared w/o the user
-	-- indicating that pushing to the git-lfs remote will expose the
-	-- encrypted data.
+	
+	when (isEncrypted c) $
+		unlessM (Annex.getState Annex.force) $
+			giveup $ unwords $
+				[ "You asked that encryption be enabled for"
+				, "this remote, but only the files that"
+				, "git-annex stores on it would be encrypted;"
+				, "anything that git push sends to it would"
+				, "not be encrypted. Even encryption=shared"
+				, "encryption keys will be stored on the"
+				, "remote for anyone who can access it to"
+				, "see."
+				, "(Use --force if you want to use this"
+				, "likely insecure configuration.)"
+				]
 	(c', _encsetup) <- encryptionSetup c gc
 
 	-- The repo is not stored in the remote log, because the same
diff --git a/doc/special_remotes/git-lfs.mdwn b/doc/special_remotes/git-lfs.mdwn
index c476185f9..ffb0e7411 100644
--- a/doc/special_remotes/git-lfs.mdwn
+++ b/doc/special_remotes/git-lfs.mdwn
@@ -41,11 +41,12 @@ store its SHA256 checksum in the git-annex branch.
 
 ## encryption notes
 
-The encryption= parameter only makes git-annex encrypt data stored on the
-remote. `git push` can also be used with the remote (it is a git repository
-after all), and data pushed to it with git will *not* be encrypted.
+The encryption= parameter only makes git-annex encrypt data it stores
+on the remote. `git push` can also be used with the remote
+(it is a git repository after all), and data pushed to it with
+git will *not* be encrypted.
 
-This makes using encryption=shared with a git-lfs special remote very
+Using encryption=shared with a git-lfs special remote is especially
 unlikely to be secure, because the encryption key is committed to the git
 repository. It would only make sense if you never pushed it to the
 remote, or trusted the remote's host to keep it secure.

expand encryption warning
diff --git a/doc/special_remotes/git-lfs.mdwn b/doc/special_remotes/git-lfs.mdwn
index 515720c71..c476185f9 100644
--- a/doc/special_remotes/git-lfs.mdwn
+++ b/doc/special_remotes/git-lfs.mdwn
@@ -19,7 +19,7 @@ the git-lfs special remote:
   at different times as long as they point to the same git-lfs repository.
 
 * `encryption` - One of "none", "hybrid", "shared", or "pubkey".
-  Required. See [[encryption]].
+  Required. See [[encryption]]. Also see the encryption notes below.
 
 * `keyid` - Specifies the gpg key to use for encryption of both the files
   git-annex stores in the repository, as well as to encrypt the git
@@ -36,14 +36,19 @@ other backend, git-annex has to additionally store the SHA256 checksum
 into the git-annex branch when storing content in git-lfs. That adds a
 small bit of size overhead to using this remote.
 
+When encrypting data sent to the git-lfs remote, git-annex always has to
+store its SHA256 checksum in the git-annex branch.
+
 ## encryption notes
 
 The encryption= parameter only makes git-annex encrypt data stored on the
-remote, `git push` can also be used with the remote (it is a git repository
+remote. `git push` can also be used with the remote (it is a git repository
 after all), and data pushed to it with git will *not* be encrypted.
 
-When encrypting data sent to the git-lfs remote, git-annex always has to
-store its SHA256 checksum in the git-annex branch.
+This makes using encryption=shared with a git-lfs special remote very
+unlikely to be secure, because the encryption key is committed to the git
+repository. It would only make sense if you never pushed it to the
+remote, or trusted the remote's host to keep it secure.
 
 ## limitations
 

remove extra blank line
diff --git a/doc/thanks/list b/doc/thanks/list
index 05eb8d3a6..f7ce6507e 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -59,7 +59,6 @@ Walltime,
 Caleb Allen, 
 TD, 
 Pedro Araújo, 
-
 Ryan Newton, 
 David W, 
 L N D, 

update
diff --git a/doc/thanks/list b/doc/thanks/list
index 6b58c7273..05eb8d3a6 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -60,3 +60,9 @@ Caleb Allen,
 TD, 
 Pedro Araújo, 
 
+Ryan Newton, 
+David W, 
+L N D, 
+EVAN HENSHAWPLATH, 
+James Read, 
+Luke Shumaker, 

expand
diff --git a/Remote/GitLFS.hs b/Remote/GitLFS.hs
index 02d83a4b6..d9617058e 100644
--- a/Remote/GitLFS.hs
+++ b/Remote/GitLFS.hs
@@ -107,6 +107,11 @@ mySetup _ mu _ c gc = do
 
 	let repo = fromMaybe (giveup "Specify url=") $
 		M.lookup "url" c
+	-- TODO: don't allow using encryption w/o the user indicating they
+	-- know it will only encrypt git-annex objects, not git pushes
+	-- TODO: don't allow using encryption=shared w/o the user
+	-- indicating that pushing to the git-lfs remote will expose the
+	-- encrypted data.
 	(c', _encsetup) <- encryptionSetup c gc
 
 	-- The repo is not stored in the remote log, because the same
diff --git a/doc/special_remotes/git-lfs.mdwn b/doc/special_remotes/git-lfs.mdwn
index 21e07fa22..515720c71 100644
--- a/doc/special_remotes/git-lfs.mdwn
+++ b/doc/special_remotes/git-lfs.mdwn
@@ -47,6 +47,9 @@ store its SHA256 checksum in the git-annex branch.
 
 ## limitations
 
+The git-lfs protocol does not support deleting content, so git-annex
+**cannot delete anything** from a git-lfs special remote.
+
 The git-lfs protocol does not support resuming uploads, and so an
 interrupted upload will have to restart from the beginning. Interrupted
 downloads will resume.
diff --git a/doc/tips/storing_data_in_git-lfs.mdwn b/doc/tips/storing_data_in_git-lfs.mdwn
index 8600941da..83945059b 100644
--- a/doc/tips/storing_data_in_git-lfs.mdwn
+++ b/doc/tips/storing_data_in_git-lfs.mdwn
@@ -22,5 +22,14 @@ url as long as it points to the same git-lfs repository.
 Note that http urls currently only allow read access to the git-lfs
 repository.
 
+Once the remote is set up, you git-annex can store and retrieve content in
+the usual ways:
+
+	git annex copy * --to lfs
+	git annex get --from lfs
+
+But, git-annex **cannot delete anything** from a git-lfs special remote,
+because the protocol does not support deletion.
+
 A git-lfs special remote also functions as a regular git remote. You can
 use things like `git push` and `git pull` with it.

note on git-lfs program
diff --git a/doc/tips/storing_data_in_git-lfs.mdwn b/doc/tips/storing_data_in_git-lfs.mdwn
index d6ab8827e..8600941da 100644
--- a/doc/tips/storing_data_in_git-lfs.mdwn
+++ b/doc/tips/storing_data_in_git-lfs.mdwn
@@ -1,6 +1,9 @@
 git-annex can store data in [git-lfs](https://git-lfs.github.com/)
 repositories, using the [[git-lfs special remote|special_remotes/git-lfs]].
 
+You do not need the git-lfs program installed to use it, just a recent
+enough version of git-annex.
+
 Here's how to initialize a git-lfs special remote on Github.
 
 	git annex initremote lfs type=git-lfs encryption=none url=git@github.com:yourname/yourrepo.git

documentation for git-lfs special remote
diff --git a/doc/special_remotes.mdwn b/doc/special_remotes.mdwn
index 0ae4346ed..0203f5778 100644
--- a/doc/special_remotes.mdwn
+++ b/doc/special_remotes.mdwn
@@ -15,6 +15,7 @@ the git history is not stored in them.
 * [[ddar]]
 * [[directory]]
 * [[gcrypt]] (encrypted git repositories!)
+* [[git-lfs]]
 * [[hook]]
 * [[rclone]]
 * [[rsync]]
diff --git a/doc/special_remotes/git-lfs.mdwn b/doc/special_remotes/git-lfs.mdwn
new file mode 100644
index 000000000..21e07fa22
--- /dev/null
+++ b/doc/special_remotes/git-lfs.mdwn
@@ -0,0 +1,64 @@
+git-annex has a special remote that lets it store content in git-lfs
+repositories.
+
+See [[tips/storing_data_in_git-lfs]] for some examples of how to use this.
+
+## configuration
+
+These parameters can be passed to `git annex initremote` to configure
+the git-lfs special remote:
+
+* `url` - Required. The url to the git-lfs repository to use.
+  Can be either a ssh url (scp-style is also accepted) or a http url.
+  But currently, a http url accesses the git-lfs repository without
+  authentication. To authenticate, you will need to use a ssh url.
+
+  This parameter needs to be specified in the initial `git annex
+  initremote` but also each time you `git annex enableremote`
+  an existing git-lfs special remote. It's fine to use different urls
+  at different times as long as they point to the same git-lfs repository.
+
+* `encryption` - One of "none", "hybrid", "shared", or "pubkey".
+  Required. See [[encryption]].
+
+* `keyid` - Specifies the gpg key to use for encryption of both the files
+  git-annex stores in the repository, as well as to encrypt the git
+  repository itself. May be repeated when multiple participants
+  should have access to the repository.
+
+## efficiency note
+
+Since git-lfs uses SHA256 checksums, git-annex needs to keep track of the
+SHA256 of content stored in it, in order to be able to retrieve that
+content. When a git-annex key uses a [[backend|backends]]
+of SHA256 or SHA256E, that's easy. But, if a git-annex key uses some
+other backend, git-annex has to additionally store the SHA256 checksum
+into the git-annex branch when storing content in git-lfs. That adds a
+small bit of size overhead to using this remote.
+
+## encryption notes
+
+The encryption= parameter only makes git-annex encrypt data stored on the
+remote, `git push` can also be used with the remote (it is a git repository
+after all), and data pushed to it with git will *not* be encrypted.
+
+When encrypting data sent to the git-lfs remote, git-annex always has to
+store its SHA256 checksum in the git-annex branch.
+
+## limitations
+
+The git-lfs protocol does not support resuming uploads, and so an
+interrupted upload will have to restart from the beginning. Interrupted
+downloads will resume.
+
+git-lfs has a concept of git ref based access control, so a user may only
+be able to send content associated with a particular git ref. git-annex
+does not currently provide any git ref, so won't work with a git-lfs server
+that uses that.
+
+git-annex only supports the "basic" git-lfs transfer adapter, but that's
+the one used by most git-lfs servers.
+
+The git-lfs protocol is designed around batching of transfers, but
+git-annex doesn't do batching. This may cause it to fall afoul of
+rate limiting of git-lfs servers when transferring a lot of files.
diff --git a/doc/tips/storing_data_in_git-lfs.mdwn b/doc/tips/storing_data_in_git-lfs.mdwn
new file mode 100644
index 000000000..d6ab8827e
--- /dev/null
+++ b/doc/tips/storing_data_in_git-lfs.mdwn
@@ -0,0 +1,23 @@
+git-annex can store data in [git-lfs](https://git-lfs.github.com/)
+repositories, using the [[git-lfs special remote|special_remotes/git-lfs]].
+
+Here's how to initialize a git-lfs special remote on Github.
+
+	git annex initremote lfs type=git-lfs encryption=none url=git@github.com:yourname/yourrepo.git
+
+If you want git-annex to encrypt the objects it stores in the remote,
+change the encryption= parameter. But be sure to read the
+[[git-lfs special remote|special_remotes/git-lfs]] page's
+**encryption notes** first!
+
+To enable the same remote in another clone of the repository,
+you'll need to provide an url to it again. It's ok to provide a different
+url as long as it points to the same git-lfs repository.
+	
+	git annex enableremote lfs url=https://github.com/yourname/yourrepo.git
+
+Note that http urls currently only allow read access to the git-lfs
+repository.
+
+A git-lfs special remote also functions as a regular git remote. You can
+use things like `git push` and `git pull` with it.

diff --git a/doc/bugs/concurrent_git-annex-copy_to_s3_special_remote_fails.mdwn b/doc/bugs/concurrent_git-annex-copy_to_s3_special_remote_fails.mdwn
new file mode 100644
index 000000000..bf98b33a7
--- /dev/null
+++ b/doc/bugs/concurrent_git-annex-copy_to_s3_special_remote_fails.mdwn
@@ -0,0 +1,61 @@
+### Please describe the problem.
+
+I'm trying to copy a directory full of photos (~9GB) to an S3 special remote. It seems to fail when running multiple jobs. The machine I am using has two cores (4 logical due to hyperthreading) and I initially used -J8 and that failed quickly. I haven't retried that yet to see if it always fails quickly but I immediately retried with -J4 and that seemed to run okay for a little over an hour and a half before failing again. This is the second large directory I've tried to copy to this remote and had a similar problem the last time (many retries seemed to allow me to get through).
+
+
+### What steps will reproduce the problem?
+
+
+### What version of git-annex are you using? On what operating system?
+
+git-annex was installed via homebrew on macos 10.14.5
+
+[[!format sh """
+
+15:23 $ git annex version
+git-annex version: 7.20190322
+build flags: Assistant Webapp Pairing S3(multipartupload)(storageclasses) WebDAV FsEvents TorrentParser MagicMime Feeds Testsuite
+dependency versions: aws-0.19 bloomfilter-2.0.1.0 cryptonite-0.25 DAV-1.3.3 feed-1.0.1.0 ghc-8.2.2 http-client-0.5.14 persistent-sqlite-2.6.4 torrent-10000.1.1 uuid-1.3.13 yesod-1.4.5
+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 BLA
+KE2B224 BLAKE2B384E BLAKE2B384 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 hook external
+operating system: darwin x86_64
+supported repository versions: 5 7
+upgrade supported from repository versions: 0 1 2 3 4 5 6
+
+"""]]
+
+
+### Please provide any additional information below.
+
+[[!format sh """
+
+22:56 $ git annex copy -J8 photos/ --to s3
+copy photos/2001/01/IMAG0003.JPG (checking s3...) (to s3...) ok
+copy photos/2001/01/IMAG0006.JPG (checking s3...) (to s3...)
+88%   319.84 KiB       68 KiB/s 0s
+copy photos/2001/01/IMAG0001-1.JPG (checking s3...) (to s3...)
+63%   255.88 KiB       25 KiB/s 6s
+copy photos/2001/01/IMAG0002.JPG (checking s3...) (to s3...)
+63%   223.89 KiB       17 KiB/s 7s
+copy photos/2001/01/IMAG0004.JPG (checking s3...) (to s3...)
+copy photos/2001/01/IMAG0005.JPG (checking s3...) (to s3...)
+80%   287.86 KiB      159 KiB/s 0s
+copy photos/2001/01/IMAG0001.JPG (checking s3...) (to s3...)
+74%   255.88 KiB       49 KiB/s 1s
+copy photos/2001/01/IMAG0002-1.JPG (checking s3...) (to s3...)
+  ParseError {errorContexts = [], errorMessage = "Failed reading: takeWhile1", errorPosition = 4:2 (285)}
+copy photos/2001/01/IMAG0007.JPG (checking s3...) (to s3...)
+10%   31.98 KiB       102 KiB/s 2s
+git-annex(21112,0x70000dd5b000) malloc: Incorrect checksum for freed object 0x7fe0b3e02bf8: probably modified after being freed.
+Corrupt value: 0x6574636f2f6e6f69
+git-annex(21112,0x70000dd5b000) malloc: *** set a breakpoint in malloc_error_break to debug
+error: git-annex died of signal 6
+
+
+"""]]
+
+### 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 a new git-annex user and besides these occasional issues with concurrent with git-annex-copy I found it really easy to get going with git-annex and to manage my imported files. In particular I really appreciate the extensive documentation!

diff --git a/doc/bugs/fails_to___96__get__96___in_parallel_for_a_freshly_clone_from_public_s3_bucket_where_versioning_info_was_forgotten.mdwn b/doc/bugs/fails_to___96__get__96___in_parallel_for_a_freshly_clone_from_public_s3_bucket_where_versioning_info_was_forgotten.mdwn
new file mode 100644
index 000000000..aa6283edc
--- /dev/null
+++ b/doc/bugs/fails_to___96__get__96___in_parallel_for_a_freshly_clone_from_public_s3_bucket_where_versioning_info_was_forgotten.mdwn
@@ -0,0 +1,90 @@
+### Please describe the problem.
+
+original report: https://github.com/datalad/datalad/issues/3583
+
+### What steps will reproduce the problem?
+
+initial get -J8 largely fails (ok for 1 file in one thread I guess) but subsequent succeeds:
+
+[[!format sh """
+hopa:/tmp
+$> git clone https://github.com/OpenNeuroDatasets/ds000248 && cd ds000248 && git annex init && git annex get -J 8 sub-01 
+Cloning into 'ds000248'...                                                                                     
+remote: Enumerating objects: 161, done.
+remote: Total 161 (delta 0), reused 0 (delta 0), pack-reused 161
+Receiving objects: 100% (161/161), 18.55 KiB | 863.00 KiB/s, done.
+Resolving deltas: 100% (20/20), done.
+CHANGES  acq-epi_T1w.json  acq-flipangle05_run-01_MEFLASH.json  acq-flipangle30_run-01_MEFLASH.json  dataset_description.json  derivatives/  sub-01/  sub-emptyroom/
+init  (merging origin/git-annex into git-annex...)
+(recording state in git...)
+
+  Remote origin not usable by git-annex; setting annex-ignore
+(Auto enabling special remote s3-PUBLIC...)
+ok
+(recording state in git...)
+get sub-01/meg/sub-01_task-audiovisual_run-01_meg.fif (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+
+  unknown export location
+
+  Unable to access these remotes: s3-PUBLIC
+
+  Try making some of these repositories available:
+  	82a4b182-753f-4d93-a59e-20cfdd4d4237 -- [s3-PUBLIC]
+   	e3612a8a-0c48-4374-9bfb-888f4010be54 -- root@1f69c4ed80cf:/datalad/ds000248
+
+  (Note that these git remotes have annex-ignore set: origin)
+failed
+get sub-01/anat/sub-01_acq-flipangle30_run-01_MEFLASH.nii.gz (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+
+  unknown export location
+
+  Unable to access these remotes: s3-PUBLIC
+
+  Try making some of these repositories available:
+  	82a4b182-753f-4d93-a59e-20cfdd4d4237 -- [s3-PUBLIC]
+   	e3612a8a-0c48-4374-9bfb-888f4010be54 -- root@1f69c4ed80cf:/datalad/ds000248
+
+  (Note that these git remotes have annex-ignore set: origin)
+failed
+get sub-01/anat/sub-01_T1w.nii.gz (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+
+  unknown export location
+
+  Unable to access these remotes: s3-PUBLIC
+
+  Try making some of these repositories available:
+  	82a4b182-753f-4d93-a59e-20cfdd4d4237 -- [s3-PUBLIC]
+   	e3612a8a-0c48-4374-9bfb-888f4010be54 -- root@1f69c4ed80cf:/datalad/ds000248
+
+  (Note that these git remotes have annex-ignore set: origin)
+failed
+get sub-01/anat/sub-01_acq-flipangle05_run-01_MEFLASH.nii.gz (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+(checksum...) ok
+(recording state in git...)
+git-annex: get: 3 failed
+
+$> git annex get -J 8 sub-01
+get sub-01/anat/sub-01_T1w.nii.gz (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+(checksum...) ok
+get sub-01/anat/sub-01_acq-flipangle30_run-01_MEFLASH.nii.gz (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+(checksum...) ok
+get sub-01/meg/sub-01_task-audiovisual_run-01_meg.fif (from s3-PUBLIC...) 
+  Remote is configured to use versioning, but no S3 version ID is recorded for this key
+(checksum...) ok
+(recording state in git...)
+
+"""]]
+
+
+### What version of git-annex are you using? On what operating system?
+
+7.20190708+git36-g32d526164-1~ndall+1
+
+
+[[!meta author=yoh]]

Added a comment: Thank you, CFBundleShortVersionString is present and matches the internal git-annex version
diff --git a/doc/bugs/CFBundleShortVersionString_is_not_incremented_with_git-annex.dmg_releases___40__downloads.kitenet.net__41__/comment_1_a97699ec3b18b9601a891d399a0f36e4._comment b/doc/bugs/CFBundleShortVersionString_is_not_incremented_with_git-annex.dmg_releases___40__downloads.kitenet.net__41__/comment_1_a97699ec3b18b9601a891d399a0f36e4._comment
new file mode 100644
index 000000000..f8b999169
--- /dev/null
+++ b/doc/bugs/CFBundleShortVersionString_is_not_incremented_with_git-annex.dmg_releases___40__downloads.kitenet.net__41__/comment_1_a97699ec3b18b9601a891d399a0f36e4._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="leej"
+ avatar="http://cdn.libravatar.org/avatar/eb1c6bd57680f694fb4658388e6de4ed"
+ subject="Thank you, CFBundleShortVersionString is present and matches the internal git-annex version"
+ date="2019-08-02T15:57:10Z"
+ content="""
+I can confirm that this works just fine with Munki tools version 3.6.2.3776.
+Thank you again, Joey
+"""]]

removed
diff --git a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_3_efd9d19b40e045c13c9a6fb8cfa9adae._comment b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_3_efd9d19b40e045c13c9a6fb8cfa9adae._comment
deleted file mode 100644
index 82a1d4386..000000000
--- a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_3_efd9d19b40e045c13c9a6fb8cfa9adae._comment
+++ /dev/null
@@ -1,13 +0,0 @@
-[[!comment format=mdwn
- username="leej"
- avatar="http://cdn.libravatar.org/avatar/eb1c6bd57680f694fb4658388e6de4ed"
- subject="Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current"
- date="2019-08-02T15:49:11Z"
- content="""
-The distribution directories are all showing 2019-07-30, but the build and distribution at downloads.kitenet.net/git-annex/OSX/current/<OSX version>/
-distributionVersion = \"7.20190709\", distributionReleasedate = 2019-07-30 20:37:03.710335378 UTC
-
-
-Let me know if you'd like a new ticket opened instead of re-opening this issue.
-
-"""]]

removed
diff --git a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_4_3ae37fac009a36170fe699c62a8f2fc5._comment b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_4_3ae37fac009a36170fe699c62a8f2fc5._comment
deleted file mode 100644
index df7a8e5a0..000000000
--- a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_4_3ae37fac009a36170fe699c62a8f2fc5._comment
+++ /dev/null
@@ -1,13 +0,0 @@
-[[!comment format=mdwn
- username="leej"
- avatar="http://cdn.libravatar.org/avatar/eb1c6bd57680f694fb4658388e6de4ed"
- subject="Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current"
- date="2019-08-02T15:49:20Z"
- content="""
-The distribution directories are all showing 2019-07-30, but the build and distribution at downloads.kitenet.net/git-annex/OSX/current/<OSX version>/
-distributionVersion = \"7.20190709\", distributionReleasedate = 2019-07-30 20:37:03.710335378 UTC
-
-
-Let me know if you'd like a new ticket opened instead of re-opening this issue.
-
-"""]]

Added a comment: Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current
diff --git a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_4_3ae37fac009a36170fe699c62a8f2fc5._comment b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_4_3ae37fac009a36170fe699c62a8f2fc5._comment
new file mode 100644
index 000000000..df7a8e5a0
--- /dev/null
+++ b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_4_3ae37fac009a36170fe699c62a8f2fc5._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="leej"
+ avatar="http://cdn.libravatar.org/avatar/eb1c6bd57680f694fb4658388e6de4ed"
+ subject="Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current"
+ date="2019-08-02T15:49:20Z"
+ content="""
+The distribution directories are all showing 2019-07-30, but the build and distribution at downloads.kitenet.net/git-annex/OSX/current/<OSX version>/
+distributionVersion = \"7.20190709\", distributionReleasedate = 2019-07-30 20:37:03.710335378 UTC
+
+
+Let me know if you'd like a new ticket opened instead of re-opening this issue.
+
+"""]]

Added a comment: Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current
diff --git a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_3_efd9d19b40e045c13c9a6fb8cfa9adae._comment b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_3_efd9d19b40e045c13c9a6fb8cfa9adae._comment
new file mode 100644
index 000000000..82a1d4386
--- /dev/null
+++ b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_3_efd9d19b40e045c13c9a6fb8cfa9adae._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="leej"
+ avatar="http://cdn.libravatar.org/avatar/eb1c6bd57680f694fb4658388e6de4ed"
+ subject="Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current"
+ date="2019-08-02T15:49:11Z"
+ content="""
+The distribution directories are all showing 2019-07-30, but the build and distribution at downloads.kitenet.net/git-annex/OSX/current/<OSX version>/
+distributionVersion = \"7.20190709\", distributionReleasedate = 2019-07-30 20:37:03.710335378 UTC
+
+
+Let me know if you'd like a new ticket opened instead of re-opening this issue.
+
+"""]]

Added a comment: Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current
diff --git a/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_2_7f88bf1d7821ea2dd0eed624563d5482._comment b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_2_7f88bf1d7821ea2dd0eed624563d5482._comment
new file mode 100644
index 000000000..3f0f5174a
--- /dev/null
+++ b/doc/bugs/downloads.kitenet.net__47__git-annex__47__OSX__47__current__47___distribution_is_7.20190508_but_7.20190615_expected/comment_2_7f88bf1d7821ea2dd0eed624563d5482._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="leej"
+ avatar="http://cdn.libravatar.org/avatar/eb1c6bd57680f694fb4658388e6de4ed"
+ subject="Currently, 7.20190730 is expected but 7.20190709-gee3885d15 present on OSX/current"
+ date="2019-08-02T15:48:52Z"
+ content="""
+The distribution directories are all showing 2019-07-30, but the build and distribution at downloads.kitenet.net/git-annex/OSX/current/<OSX version>/
+distributionVersion = \"7.20190709\", distributionReleasedate = 2019-07-30 20:37:03.710335378 UTC
+
+
+Let me know if you'd like a new ticket opened instead of re-opening this issue.
+
+"""]]

skeleton git-lfs special remote
This is a special remote and a git remote at the same time; git can pull
and push to it and git-annex can use it as a special remote.
Remote.Git has to check if it's configured as a git-lfs special remote
and sets it up as one if so.
Object methods not implemented yet.
diff --git a/Remote/Git.hs b/Remote/Git.hs
index 61b58a489..6e9af5dd5 100644
--- a/Remote/Git.hs
+++ b/Remote/Git.hs
@@ -51,6 +51,7 @@ import Remote.Helper.Messages
 import Remote.Helper.ExportImport
 import qualified Remote.Helper.Ssh as Ssh
 import qualified Remote.GCrypt
+import qualified Remote.GitLFS
 import qualified Remote.P2P
 import qualified Remote.Helper.P2P as P2PHelper
 import P2P.Address
@@ -144,6 +145,7 @@ configRead autoinit r = do
 gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
 gen r u c gc
 	| Git.GCrypt.isEncrypted r = Remote.GCrypt.chainGen r u c gc
+	| remoteAnnexGitLFS gc = Remote.GitLFS.gen r u c gc
 	| otherwise = case repoP2PAddress r of
 		Nothing -> do
 			st <- mkState r u gc
diff --git a/Remote/GitLFS.hs b/Remote/GitLFS.hs
new file mode 100644
index 000000000..d46e97160
--- /dev/null
+++ b/Remote/GitLFS.hs
@@ -0,0 +1,130 @@
+{- Using git-lfs as a remote.
+ -
+ - Copyright 2019 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module Remote.GitLFS (remote, gen) where
+
+import Annex.Common
+import Types.Remote
+import Annex.Url
+import Types.Creds
+import qualified Git
+import Config
+import Config.Cost
+import Remote.Helper.Special
+import Remote.Helper.ExportImport
+import Remote.Helper.Git
+import Annex.Ssh
+import Annex.UUID
+import Utility.SshHost
+import qualified Utility.GitLFS as LFS
+
+import Control.Concurrent.STM
+import qualified Data.Map as M
+
+remote :: RemoteType
+remote = RemoteType
+	{ typename = "git-lfs"
+	-- Remote.Git takes care of enumerating git-lfs remotes too,
+	-- and will call our gen on them.
+	, enumerate = const (return [])
+	, generate = gen
+	, setup = mySetup
+	, exportSupported = exportUnsupported
+	, importSupported = importUnsupported
+	}
+
+type LFSHandle = TVar (String, Maybe LFS.Endpoint)
+
+gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
+gen r u c gc = do
+	handle <- liftIO $ newTVarIO (lfsrepo, Nothing)
+	cst <- remoteCost gc expensiveRemoteCost
+	return $ Just $ specialRemote' specialcfg c
+		(simplyPrepare $ store handle)
+		(simplyPrepare $ retrieve handle)
+		(simplyPrepare $ remove handle)
+		(simplyPrepare $ checkKey handle)
+		(this cst)
+  where
+	this cst = Remote
+		{ uuid = u
+		, cost = cst
+		, name = Git.repoDescribe r
+		, storeKey = storeKeyDummy
+		, retrieveKeyFile = retreiveKeyFileDummy
+		, retrieveKeyFileCheap = retrieveCheap
+		-- content stored on git-lfs is hashed with SHA256
+		-- no matter what git-annex key it's for, and the hash
+		-- is checked on download
+		, retrievalSecurityPolicy = RetrievalAllKeysSecure
+		, removeKey = removeKeyDummy
+		, lockContent = Nothing
+		, checkPresent = checkPresentDummy
+		, checkPresentCheap = False
+		, exportActions = exportUnsupported
+		, importActions = importUnsupported
+		, whereisKey = Nothing
+		, remoteFsck = Nothing
+		, repairRepo = Nothing
+		, config = c
+		, getRepo = return r
+		, gitconfig = gc
+		, localpath = Nothing
+		, remotetype = remote
+		, availability = GloballyAvailable
+		, readonly = False
+		-- content cannot be removed from a git-lfs repo
+		, appendonly = True
+		, mkUnavailable = return Nothing
+		, getInfo = gitRepoInfo (this cst)
+		, claimUrl = Nothing
+		, checkUrl = Nothing
+		}
+	lfsrepo = fromMaybe
+		(giveup "remote url is not configured")
+		(M.lookup "url" $ Git.config r)
+	specialcfg = (specialRemoteCfg c)
+		-- chunking would not improve git-lfs
+		{ chunkConfig = NoChunks
+		}
+
+mySetup :: SetupStage -> Maybe UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> Annex (RemoteConfig, UUID)
+mySetup _ mu _ c gc = do
+	u <- maybe (liftIO genUUID) return mu
+
+	let repo = fromMaybe (giveup "Specify url=") $
+		M.lookup "url" c
+	(c', _encsetup) <- encryptionSetup c gc
+
+	-- The repo is not stored in the remote log, because the same
+	-- git-lfs repo can be accessed using different urls by different
+	-- people (eg over ssh or http).
+	--
+	-- Instead, set up remote.name.url to point to the repo,
+	-- (so it's also usable by git as a non-special remote),
+	-- and set remote.name.git-lfs = true
+	let c'' = M.delete "repo" c'
+	gitConfigSpecialRemote u c'' [("git-lfs", "true")]
+	setConfig (ConfigKey ("remote." ++ getRemoteName c ++ ".url")) repo
+	return (c'', u)
+
+store :: LFSHandle -> Storer
+store h = fileStorer $ \k src p -> undefined
+
+retrieve :: LFSHandle -> Retriever
+retrieve h = byteRetriever $ \k sink -> undefined
+
+retrieveCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
+retrieveCheap _ _ _ = return False
+
+checkKey :: LFSHandle -> CheckPresent
+checkKey h key = undefined
+
+remove :: LFSHandle -> Remover
+remove h key = do
+	warning "git-lfs does not support removing content"
+	return False
diff --git a/Remote/List.hs b/Remote/List.hs
index b1cd8ff6a..d4ed4dfe2 100644
--- a/Remote/List.hs
+++ b/Remote/List.hs
@@ -40,6 +40,7 @@ import qualified Remote.Adb
 import qualified Remote.Tahoe
 import qualified Remote.Glacier
 import qualified Remote.Ddar
+import qualified Remote.GitLFS
 import qualified Remote.Hook
 import qualified Remote.External
 
@@ -63,6 +64,7 @@ remoteTypes = map adjustExportImportRemoteType
 	, Remote.Tahoe.remote
 	, Remote.Glacier.remote
 	, Remote.Ddar.remote
+	, Remote.GitLFS.remote
 	, Remote.Hook.remote
 	, Remote.External.remote
 	]
diff --git a/Types/GitConfig.hs b/Types/GitConfig.hs
index 0bc72d402..7976f08e9 100644
--- a/Types/GitConfig.hs
+++ b/Types/GitConfig.hs
@@ -263,6 +263,7 @@ data RemoteGitConfig = RemoteGitConfig
 	, remoteAnnexAndroidDirectory :: Maybe FilePath
 	, remoteAnnexAndroidSerial :: Maybe String
 	, remoteAnnexGCrypt :: Maybe String
+	, remoteAnnexGitLFS :: Bool
 	, remoteAnnexDdarRepo :: Maybe String
 	, remoteAnnexHookType :: Maybe String
 	, remoteAnnexExternalType :: Maybe String
@@ -321,6 +322,7 @@ extractRemoteGitConfig r remotename = do
 		, remoteAnnexAndroidDirectory = notempty $ getmaybe "androiddirectory"
 		, remoteAnnexAndroidSerial = notempty $ getmaybe "androidserial"
 		, remoteAnnexGCrypt = notempty $ getmaybe "gcrypt"
+		, remoteAnnexGitLFS = getbool "git-lfs" False
 		, remoteAnnexDdarRepo = getmaybe "ddarrepo"
 		, remoteAnnexHookType = notempty $ getmaybe "hooktype"
 		, remoteAnnexExternalType = notempty $ getmaybe "externaltype"
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 7af5f1265..dc9868e91 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn

(Diff truncated)
fix names of per-remote git config keys
These are all prefixed by annex- and always have been, the docs were just
wrong.
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 212c78985..7af5f1265 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -1546,71 +1546,71 @@ Here are all the supported configuration settings.
 
   For example, to use the wipe command, set it to `wipe -f %file`.
 
-* `remote.<name>.rsyncurl`
+* `remote.<name>.annex-rsyncurl`
 
   Used by rsync special remotes, this configures
   the location of the rsync repository to use. Normally this is automatically
   set up by `git annex initremote`, but you can change it if needed.
 
-* `remote.<name>.buprepo`
+* `remote.<name>.annex-buprepo`
 
   Used by bup special remotes, this configures
   the location of the bup repository to use. Normally this is automatically
   set up by `git annex initremote`, but you can change it if needed.
 
-* `remote.<name>.ddarrepo`
+* `remote.<name>.annex-ddarrepo`
 
   Used by ddar special remotes, this configures
   the location of the ddar repository to use. Normally this is automatically
   set up by `git annex initremote`, but you can change it if needed.
 
-* `remote.<name>.directory`
+* `remote.<name>.annex-directory`
 
   Used by directory special remotes, this configures
   the location of the directory where annexed files are stored for this
   remote. Normally this is automatically set up by `git annex initremote`,
   but you can change it if needed.
 
-* `remote.<name>.adb`
+* `remote.<name>.annex-adb`
 
   Used to identify remotes on Android devices accessed via adb.
   Normally this is automatically set up by `git annex initremote`.
 
-* `remote.<name>.androiddirectory`
+* `remote.<name>.annex-androiddirectory`
 
   Used by adb special remotes, this is the directory on the Android
   device where files are stored for this remote. Normally this is
   automatically set up by `git annex initremote`, but you can change
   it if needed.
 
-* `remote.<name>.androidserial`
+* `remote.<name>.annex-androidserial`
 
   Used by adb special remotes, this is the serial number of the Android
   device used by the remote. Normally this is automatically set up by
   `git annex initremote`, but you can change it if needed, eg when
   upgrading to a new Android device.
 
-* `remote.<name>.s3`
+* `remote.<name>.annex-s3`
 
   Used to identify Amazon S3 special remotes.
   Normally this is automatically set up by `git annex initremote`.
 
-* `remote.<name>.glacier`
+* `remote.<name>.annex-glacier`
 
   Used to identify Amazon Glacier special remotes.
   Normally this is automatically set up by `git annex initremote`.
 
-* `remote.<name>.webdav`
+* `remote.<name>.annex-webdav`
 
   Used to identify webdav special remotes.
   Normally this is automatically set up by `git annex initremote`.
 
-* `remote.<name>.tahoe`
+* `remote.<name>.annex-tahoe`
 
   Used to identify tahoe special remotes.
   Points to the configuration directory for tahoe.
 
-* `remote.<name>.gcrypt`
+* `remote.<name>.annex-gcrypt`
 
   Used to identify gcrypt special remotes.
   Normally this is automatically set up by `git annex initremote`.
@@ -1619,7 +1619,7 @@ Here are all the supported configuration settings.
   If the gcrypt remote is accessible over ssh and has git-annex-shell
   available to manage it, it's set to "shell".
 
-* `remote.<name>.hooktype`, `remote.<name>.externaltype`
+* `remote.<name>.annex-hooktype`, `remote.<name>.annex-externaltype`
 
   Used by hook special remotes and external special remotes to record
   the type of the remote.

comment
diff --git a/doc/todo/borg_special_remote/comment_6_a6945345a752b166dc683484d80dfcc2._comment b/doc/todo/borg_special_remote/comment_6_a6945345a752b166dc683484d80dfcc2._comment
new file mode 100644
index 000000000..80bed89d7
--- /dev/null
+++ b/doc/todo/borg_special_remote/comment_6_a6945345a752b166dc683484d80dfcc2._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2019-08-01T16:34:22Z"
+ content="""
+I made a restic repo with 2000 single-file snapshots.
+Adding the first snapshot took 0.55s. Adding the 2000th
+snapshot took 1.10s.
+
+So that's a very big scalability problem with using restic with single-file
+snapshots.
+
+2000 files in a directory is not going to cause that kind of slowdown;
+my guess is restic needs to load all past snapshots, or something like
+that.
+"""]]

comment
diff --git a/doc/todo/borg_special_remote/comment_5_5b39e3fbf480e0e558e7fb4466798124._comment b/doc/todo/borg_special_remote/comment_5_5b39e3fbf480e0e558e7fb4466798124._comment
new file mode 100644
index 000000000..49a7c7e14
--- /dev/null
+++ b/doc/todo/borg_special_remote/comment_5_5b39e3fbf480e0e558e7fb4466798124._comment
@@ -0,0 +1,38 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2019-08-01T16:02:06Z"
+ content="""
+Half a second to store a single annex object with restic is pretty slow,
+and that's before the snapshots directory gets bloated with a hundred
+thousand files.
+
+I wonder if my original idea up top was not a better approach: Let these
+backup tools back up a whole annex repo (or at least .git/annex/objects),
+and then make git-annex interoperate with the backups by peering inside
+them and learning what has been backed up.
+
+In the meantime, git-annex has gotten tree import facilities,
+which is a similar concept, of listing content in a data store
+and so learning what's stored in there, and then being able to
+retrieve objects out of that data store on demand.
+
+Importing annex objects from a backup is not quite the same as a tree
+import, because it wouldn't result in any kind of file tree that
+you'd want to merge back into your git repo. Also tree importing has
+to download files in order to hash them, while in this case the
+object's annex key can be seen in the backup.
+
+But from a user perspective it could be quite similar, something like:
+
+	git annex initremote restic type=restic repolocation=...
+	git annex import --from restic
+	git annex get
+
+That would use `restic list snapshots` and then `restic ls` each
+snapshot and find filenames that look like annex keys
+(perhaps looking for part of the annex directory structure to avoid
+false positives). Keys it found would be marked as present in
+the remote, and the snapshot(s) that contain them recorded in
+the git-annex branch for use by git-annex get.
+"""]]

link to contact
diff --git a/doc/security.mdwn b/doc/security.mdwn
index c88b2106b..2892e3c3e 100644
--- a/doc/security.mdwn
+++ b/doc/security.mdwn
@@ -1,4 +1,7 @@
 Information about all known security holes in git-annex, and their fixes.
 Subscribe to the RSS feed to be kept up to date.
 
+If you have discovered a security hole and wish to report it privately, see
+[[contact]].
+
 [[!inline pages="./security/* and !./security/*/* and !*/Discussion" rootpage="security" show="0"]]

added bug report about test suite failures on Windows
diff --git a/doc/bugs/test_suite_fails_on_windows.mdwn b/doc/bugs/test_suite_fails_on_windows.mdwn
new file mode 100644
index 000000000..b6cb9a0bd
--- /dev/null
+++ b/doc/bugs/test_suite_fails_on_windows.mdwn
@@ -0,0 +1,687 @@
+### Please describe the problem.
+Running the test suite on windows gives test failures.
+
+### What steps will reproduce the problem?
+Install Git for Windows (64-bit), install git-annex into the Git installation dir, open Git bash, run git-annex-test .
+
+### What version of git-annex are you using? On what operating system?
+7.20190730-ga63bf35dc on Windows 10
+
+### 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
+
+MINGW64_NT-10.0-17763 WPAE9-305 3.0.7-338.x86_64 2019-04-30 21:52 UTC x86_64 Msys
+git-annex version: 7.20190730-ga63bf35dc
+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.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 hook external
+operating system: mingw32 x86_64
+supported repository versions: 5 7
+upgrade supported from repository versions: 2 3 4 5 6
+Tests
+  QuickCheck
+    prop_encode_decode_roundtrip:                         OK (0.11s)
+      +++ OK, passed 1000 tests.
+    prop_encode_c_decode_c_roundtrip:                     OK (0.09s)
+      +++ OK, passed 1000 tests.
+    prop_isomorphic_key_encode:                           OK (0.04s)
+      +++ OK, passed 1000 tests.
+    prop_isomorphic_shellEscape:                          OK (0.02s)
+      +++ OK, passed 1000 tests.
+    prop_isomorphic_shellEscape_multiword:                OK (0.85s)
+      +++ OK, passed 1000 tests.
+    prop_isomorphic_configEscape:                         OK (0.02s)
+      +++ OK, passed 1000 tests.
+    prop_parse_show_Config:                               OK (0.05s)
+      +++ OK, passed 1000 tests.
+    prop_upFrom_basics:                                   OK (0.02s)
+      +++ OK, passed 1000 tests.
+    prop_relPathDirToFile_basics:                         OK (0.02s)
+      +++ OK, passed 1000 tests.
+    prop_relPathDirToFile_regressionTest:                 OK
+      +++ OK, passed 1 test.
+    prop_cost_sane:                                       OK
+      +++ OK, passed 1 test.
+    prop_matcher_sane:                                    OK
+      +++ OK, passed 1 test.
+    prop_HmacSha1WithCipher_sane:                         OK
+      +++ OK, passed 1 test.
+    prop_VectorClock_sane:                                OK
+      +++ OK, passed 1 test.
+    prop_addMapLog_sane:                                  OK
+      +++ OK, passed 1 test.
+    prop_verifiable_sane:                                 OK (0.08s)
+      +++ OK, passed 1000 tests.
+    prop_segment_regressionTest:                          OK
+      +++ OK, passed 1 test.
+    prop_read_write_transferinfo:                         OK (0.04s)
+      +++ OK, passed 1000 tests.
+    prop_read_show_inodecache:                            OK (0.02s)
+      +++ OK, passed 1000 tests.
+    prop_parse_build_presence_log:                        OK (1.43s)
+      +++ OK, passed 1000 tests.
+    prop_parse_build_contentidentifier_log:               OK (1.43s)
+      +++ OK, passed 1000 tests.
+    prop_read_show_TrustLevel:                            OK
+      +++ OK, passed 1 test.
+    prop_parse_build_TrustLevelLog:                       OK
+      +++ OK, passed 1 test.
+    prop_hashes_stable:                                   OK
+      +++ OK, passed 1 test.
+    prop_mac_stable:                                      OK
+      +++ OK, passed 1 test.
+    prop_schedule_roundtrips:                             OK
+      +++ OK, passed 1000 tests.
+    prop_past_sane:                                       OK
+      +++ OK, passed 1 test.
+    prop_duration_roundtrips:                             OK
+      +++ OK, passed 1000 tests.
+    prop_metadata_sane:                                   OK (0.87s)
+      +++ OK, passed 1000 tests.
+    prop_metadata_serialize:                              OK (1.09s)
+      +++ OK, passed 1000 tests.
+    prop_branchView_legal:                                OK (0.72s)
+      +++ OK, passed 1000 tests.
+    prop_viewPath_roundtrips:                             OK (0.04s)
+      +++ OK, passed 1000 tests.
+    prop_view_roundtrips:                                 OK (0.48s)
+      +++ OK, passed 1000 tests.
+    prop_viewedFile_rountrips:                            OK (0.02s)
+      +++ OK, passed 1000 tests.
+    prop_b64_roundtrips:                                  OK
+      +++ OK, passed 1000 tests.
+    prop_standardGroups_parse:                            OK
+      +++ OK, passed 1 test.
+  Unit Tests v7 unlocked
+    add dup:                                              Init Tests
+  init: init test repo 
+  Detected a filesystem without fifo support.
+
+  Disabling ssh connection caching.
+
+  Detected a crippled filesystem.
+
+  Entering an adjusted branch where files are unlocked as this filesystem does not support locked files.
+ok
+(recording state in git...)
+OK (2.25s)
+  add:  git-annex.exe: NUL: openFile: does not exist (No such file or directory)
+error: external filter 'git-annex smudge --clean -- %f' failed 1
+error: external filter 'git-annex smudge --clean -- %f' failed
+FAIL (0.52s)
+    .\Test\Framework.hs:347:
+    foo failed to look up key
+
+1 out of 2 tests failed (2.78s)
+FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    add extras:                                           FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    export_import:                                        FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    export_import_subdir:                                 FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    shared clone:                                         FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    log:                                                  FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    import:                                               FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    reinject:                                             FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    unannex (no copy):                                    FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    unannex (with copy):                                  FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    drop (no remote):                                     FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    drop (with remote):                                   FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    drop (untrusted remote):                              FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    get:                                                  FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    get (ssh remote):                                     FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    move:                                                 FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    move (ssh remote):                                    FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    copy:                                                 FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):
+        error, called at .\Test\Framework.hs:431:33 in main:Test.Framework
+    lock:                                                 FAIL
+      Exception: init tests failed! cannot continue
+      CallStack (from HasCallStack):

(Diff truncated)
Added a comment: SnapChat Error
diff --git a/doc/forum/How_to_remove_annex_on_osx__63__/comment_2_e1e99510ba234db1b8473aca607b60c6._comment b/doc/forum/How_to_remove_annex_on_osx__63__/comment_2_e1e99510ba234db1b8473aca607b60c6._comment
new file mode 100644
index 000000000..876aee0bb
--- /dev/null
+++ b/doc/forum/How_to_remove_annex_on_osx__63__/comment_2_e1e99510ba234db1b8473aca607b60c6._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="andrew7278"
+ avatar="http://cdn.libravatar.org/avatar/834467aeb2f15d1e260f4b6209d52939"
+ subject="SnapChat Error"
+ date="2019-07-31T11:04:58Z"
+ content="""
+I am recently facing some few errors with the SnapChat and I cannot connect with anyone with this. I have tried a lot to get this issue solved but failed. I have even reinstalled it as per the instruction, given in <https://supportphonenumberaustralia.com/snapchat-support-phone-number/>, but all was in vain. Can anyone suggest me any solution in this regards?
+"""]]

add news item for git-annex 7.20190730
diff --git a/doc/news/version_7.20190503.mdwn b/doc/news/version_7.20190503.mdwn
deleted file mode 100644
index 2e4912788..000000000
--- a/doc/news/version_7.20190503.mdwn
+++ /dev/null
@@ -1,30 +0,0 @@
-git-annex 7.20190503 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * adb special remote supports being configured with importtree=yes,
-     to allow git-annex import of files from an Android device. This can be
-     combined with exporttree=yes and git-annex export used to send changes
-     back to the Android device.
-   * S3 special remote supports being configured with importtree=yes,
-     to allow git-annex import of files from a S3 bucket. This can be
-     combined with exporttree=yes and git-annex export used to send changes
-     back to the S3 bucket.
-   * S3: When versioning is enabled on a bucket, importing from it will
-     import old versions of files that were written to the bucket as well
-     as the current versions. A git history is synthesized to reflect the way
-     the bucket changed over time.
-   * Fix bug that caused importing from a special remote to repeatedly
-     download unchanged files when multiple files in the remote have the same
-     content.
-   * Made git-annex sync --content much faster when all the remotes it's
-     syncing with are export/import remotes.
-   * sync: When listing contents on an import remote fails, proceed with
-     other syncing instead of aborting.
-   * renameremote: New command, changes the name that is used to enable
-     a special remote. Especially useful when you want to reuse the name
-     of an old remote for something new.
-   * Drop support for building with aws older than 0.14.
-   * info: Show when a remote is configured with importtree.
-   * Added mimeencoding= term to annex.largefiles expressions.
-     This is probably mostly useful to match non-text files with eg
-     "mimeencoding=binary"
-   * git-annex matchexpression: Added --mimeencoding option."""]]
\ No newline at end of file
diff --git a/doc/news/version_7.20190730.mdwn b/doc/news/version_7.20190730.mdwn
new file mode 100644
index 000000000..40b4d9587
--- /dev/null
+++ b/doc/news/version_7.20190730.mdwn
@@ -0,0 +1,25 @@
+git-annex 7.20190730 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Improved probing when CoW copies can be made between files on the same
+     drive. Now supports CoW between BTRFS subvolumes. And, falls back to rsync
+     instead of using cp when CoW won't work, eg copies between repos on the
+     same EXT4 filesystem.
+   * Add BLAKE2BP512 and BLAKE2BP512E backends, using a blake2 variant
+     optimised for 4-way CPUs.
+   * Support running v7 upgrade in a repo where there is no branch checked
+     out, but HEAD is set directly to some other ref.
+   * Windows build no longer ships with a copy of rsync, since that is only
+     used any more to access rsync special remotes or remotes with a very
+     old version of git-annex-shell.
+   * Windows build is now 64 bit, and using it with the 64 bit git for
+     Windows is fully supported.
+   * Windows problems with long filenames should be fixed now,
+     since the Windows build is made with a newer ghc version that works
+     around the problems.
+   * stack.yaml: Build with http-client-0.5.14 to get a bug fix to http header
+     parsing.
+   * Drop support for building with ghc older than 8.4.4,
+     and with older versions of serveral haskell libraries.
+   * Support building with socks-0.6 and persistant-template-2.7.
+   * Corrected some license statements.
+     Thanks, Sean Whitton."""]]
\ No newline at end of file

Support building with socks-0.6 and persistant-template-2.7
persistent-template now needs UndecidableInstances.
socks changed defaultSocksConf to take a SockAddr.
diff --git a/CHANGELOG b/CHANGELOG
index 3c45f6830..6f7f9afac 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,7 @@ git-annex (7.20190730) upstream; urgency=medium
     parsing.
   * Drop support for building with ghc older than 8.4.4,
     and with older versions of serveral haskell libraries.
+  * Support building with socks-0.6 and persistant-template-2.7.
   * Corrected some license statements.
     Thanks, Sean Whitton.
 
diff --git a/Database/ContentIdentifier.hs b/Database/ContentIdentifier.hs
index 4180c5854..f9cb0d1cd 100644
--- a/Database/ContentIdentifier.hs
+++ b/Database/ContentIdentifier.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts, EmptyDataDecls #-}
 {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Database.ContentIdentifier (
 	ContentIdentifierHandle,
diff --git a/Database/Export.hs b/Database/Export.hs
index 3d8b7f993..0da0173fa 100644
--- a/Database/Export.hs
+++ b/Database/Export.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-}
 {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Database.Export (
 	ExportHandle,
diff --git a/Database/Fsck.hs b/Database/Fsck.hs
index affac558b..c0c40151c 100644
--- a/Database/Fsck.hs
+++ b/Database/Fsck.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-}
 {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Database.Fsck (
 	FsckHandle,
diff --git a/Database/Keys/SQL.hs b/Database/Keys/SQL.hs
index 6dd870afc..2314a8dae 100644
--- a/Database/Keys/SQL.hs
+++ b/Database/Keys/SQL.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-}
 {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Database.Keys.SQL where
 
diff --git a/Utility/Tor.hs b/Utility/Tor.hs
index 427fb100b..094c91aac 100644
--- a/Utility/Tor.hs
+++ b/Utility/Tor.hs
@@ -5,6 +5,8 @@
  - Licensed under the GNU AGPL version 3 or higher.
  -}
 
+{-# LANGUAGE CPP #-}
+
 module Utility.Tor where
 
 import Common
@@ -37,7 +39,12 @@ connectHiddenService (OnionAddress address) port = do
 	return s
   where
 	torsocksport = 9050
+#if MIN_VERSION_socks(0,6,0)
+	torsockconf = defaultSocksConf $ SockAddrInet torsocksport $
+		tupleToHostAddress (127,0,0,1)
+#else
 	torsockconf = defaultSocksConf "127.0.0.1" torsocksport
+#endif
 	socksdomain = SocksAddrDomainName (BU8.fromString address)
 	socksaddr = SocksAddress socksdomain (fromIntegral port)
 
diff --git a/doc/todo/Compatibility_with_socks-0.6_and_persistant-template-2.7.mdwn b/doc/todo/Compatibility_with_socks-0.6_and_persistant-template-2.7.mdwn
index 8c71e5887..b8b35cefd 100644
--- a/doc/todo/Compatibility_with_socks-0.6_and_persistant-template-2.7.mdwn
+++ b/doc/todo/Compatibility_with_socks-0.6_and_persistant-template-2.7.mdwn
@@ -3,3 +3,5 @@ The current Hackage version (7.20190615) only compiles with the constraints sock
 The compiler errors can be fixed with the attached patches.
 
 In the case of the socks changes (for Tor), I am not sure if it will actually work correctly.
+
+> Found the necessary changes to get it to compile. [[done]] --[[Joey]]

remove spam
diff --git a/doc/forum/Syncing_with_an_encrypted_remote_from_a_different_computer__63__/comment_5_f14a08e15ba5e096fc39c05a37f3add7._comment b/doc/forum/Syncing_with_an_encrypted_remote_from_a_different_computer__63__/comment_5_f14a08e15ba5e096fc39c05a37f3add7._comment
deleted file mode 100644
index 132b4f09c..000000000
--- a/doc/forum/Syncing_with_an_encrypted_remote_from_a_different_computer__63__/comment_5_f14a08e15ba5e096fc39c05a37f3add7._comment
+++ /dev/null
@@ -1,9 +0,0 @@
-[[!comment format=mdwn
- username="ahmadabi787@4794191381bef93a2daa0515a85ff953cba9b3e0"
- nickname="ahmadabi787"
- avatar="http://cdn.libravatar.org/avatar/f3c997e16d01953ace5940e35a491f5d"
- subject="Technical support"
- date="2019-07-26T07:12:59Z"
- content="""
- Remote Desktop can be secured using SSL/TLS in Windows Vista, Windows 7, and Windows Server 2003/2008. While Remote Desktop is more secure than remote administration tools such as VNC that do not encrypt the entire session, any time Administrator access to a system is granted remotely there are risks. If anyone faces TV issues connect [LG TV Repair](https://www.techsupportdubai.com/lg-tv-repair/)
-"""]]
diff --git a/doc/install/Android/comment_1_44984732ac139f8921f5044d68ef7817._comment b/doc/install/Android/comment_1_44984732ac139f8921f5044d68ef7817._comment
deleted file mode 100644
index 16283fdd6..000000000
--- a/doc/install/Android/comment_1_44984732ac139f8921f5044d68ef7817._comment
+++ /dev/null
@@ -1,13 +0,0 @@
-[[!comment format=mdwn
- username="geonemax67@f507d88f591246c5ff7de3b1f7fb2823684a789b"
- nickname="geonemax67"
- avatar="http://cdn.libravatar.org/avatar/74a24c06b9fbb063465f13ece001186c"
- subject="SAMSUNG TV Repair Dubai"
- date="2019-07-29T11:14:48Z"
- content="""
-Git-annex repositories consist of symlinks that are checked into git, and in turn point at the content of large files that are stored in .git/annex/objects/. 
-Direct mode gets rid of the symlinks. The advantage of direct mode is that you can access files directly, including modifying them.
-Enjoyed reading the article above, really explains steps to install git-annex in detail, the article is very interesting and effective.
-I learn new information from your article. Thank you for this post.
-And if you are looking for Tv repair connect with <a href=\"https://helpmeta.blogspot.com/2019/07/how-to-set-up-your-samsung-smart-tv-to.html\">SAMSUNG TV Repair Dubai</a> they provide the best service.
-"""]]