Recent changes to this wiki:

diff --git a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
index 861673f..2dfd694 100644
--- a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
+++ b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
@@ -23,6 +23,7 @@ Plus, og+r permissions can actually be important for setups like serving content
     cd dir2
     git annex get
     ctrl^c
+    git annex get
     ls -lL
     ... see different perms
 

diff --git a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
index bb6870b..861673f 100644
--- a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
+++ b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
@@ -14,8 +14,8 @@ Plus, og+r permissions can actually be important for setups like serving content
     cd dir1
     git init
     git annex init
-    touch some-small-file
-    truncate -s 10G some-large-file
+    touch a
+    truncate -s 10G b
     git annex add .
     git commit -m 'new'
 

diff --git a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
index 30dfb6e..bb6870b 100644
--- a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
+++ b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
@@ -11,6 +11,22 @@ Plus, og+r permissions can actually be important for setups like serving content
 
 ### What steps will reproduce the problem?
 
+    cd dir1
+    git init
+    git annex init
+    touch some-small-file
+    truncate -s 10G some-large-file
+    git annex add .
+    git commit -m 'new'
+
+    git clone localhost:/path/to/dir1 dir2
+    cd dir2
+    git annex get
+    ctrl^c
+    ls -lL
+    ... see different perms
+
+
 
 ### What version of git-annex are you using? On what operating system?
 

diff --git a/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
new file mode 100644
index 0000000..30dfb6e
--- /dev/null
+++ b/doc/bugs/git-annex_clears_files__39___og+r_permissions_when_rsync_transfer_is_interrupted_and_resumed.mdwn
@@ -0,0 +1,28 @@
+### Please describe the problem.
+
+umask is 022 on both hosts
+If one does ls -lL on source repo, the files are shown 644.
+
+Now, "git annex get" from a clone done over ssh generally preserves 644 ... except if the transfer (rsync) is interrupted, and then resumed.
+In fact, looks like the temp files in .git/annex/tmp have the og+r bits cleared during the resumed transfer.
+
+So this is inconsistent: I don't see why permissions should be different, depending whether or not there was an interruption in the transfer.
+Plus, og+r permissions can actually be important for setups like serving contents using Samba.
+
+### What steps will reproduce the problem?
+
+
+### What version of git-annex are you using? On what operating system?
+
+git-annex version: 5.20140411-gda795e0
+Linux
+
+### Please provide any additional information below.
+
+[[!format sh """
+# If you can, paste a complete transcript of the problem occurring here.
+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log
+
+
+# End of transcript or log.
+"""]]

Added a comment: raspbian
diff --git a/doc/forum/new_linux_arm_tarball_build/comment_10_5f9735ec62478c99b8c814055206cff0._comment b/doc/forum/new_linux_arm_tarball_build/comment_10_5f9735ec62478c99b8c814055206cff0._comment
new file mode 100644
index 0000000..eb3995e
--- /dev/null
+++ b/doc/forum/new_linux_arm_tarball_build/comment_10_5f9735ec62478c99b8c814055206cff0._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawmH9ARM62C6zcEpzh2muCs4wq-GkLRntgQ"
+ nickname="Randy"
+ subject="raspbian"
+ date="2014-04-16T10:59:10Z"
+ content="""
+This works fairly well for me on Raspian. However I am getting the same error as Justin. 
+
+    ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded: ignored.
+
+I'm ignoring the errors for now, but it's a lot of noise that actually makes it slightly difficult to see the important output.
+"""]]

fix typo
diff --git a/doc/devblog/day_133__db_and_bugfixes.mdwn b/doc/devblog/day_133__db_and_bugfixes.mdwn
index b844708..5ba1df2 100644
--- a/doc/devblog/day_133__db_and_bugfixes.mdwn
+++ b/doc/devblog/day_133__db_and_bugfixes.mdwn
@@ -4,7 +4,7 @@ several stages, starting with using it for generating views, and ending(?)
 with using it for direct mode file mappings.
 
 Not sure I'm ready to dive into that yet, so instead spent the rest of the
-day working on small bugfixes and improvemnts. Only two significant ones..
+day working on small bugfixes and improvements. Only two significant ones..
 
 Made the webapp use a constant time string comparison (from `securemem`)
 to check if its auth token is valid. This could help avoid a potential

fix typos.
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index 56afa40..270ceaa 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -137,9 +137,9 @@ encryption. Encryption is not part of this design.
 (XMPP does not do end-to-end encryption, but might be supported
 transitionally.)
 
-Ditto for authentication that we're talking to who we indend to talk to.
-Any public key data etc used for authenticion is part of the remote's
-configuration (or hidden away in a secure chmodded file, if neccesary).
+Ditto for authentication that we're talking to who we intend to talk to.
+Any public key data etc used for authentication is part of the remote's
+configuration (or hidden away in a secure chmodded file, if necessary).
 This design does not concern itself with authenticating the remote node,
 it just takes the auth token and uses it.
 

reinit: New command that can initialize a new reposotory using the configuration of a previously known repository. Useful if a repository got deleted and you want to clone it back the way it was.
diff --git a/Annex/Init.hs b/Annex/Init.hs
index 0cb4187..637b130 100644
--- a/Annex/Init.hs
+++ b/Annex/Init.hs
@@ -11,6 +11,7 @@ module Annex.Init (
 	ensureInitialized,
 	isInitialized,
 	initialize,
+	initialize',
 	uninitialize,
 	probeCrippledFileSystem,
 ) where
@@ -60,6 +61,17 @@ genDescription Nothing = do
 initialize :: Maybe String -> Annex ()
 initialize mdescription = do
 	prepUUID
+	initialize'
+
+	u <- getUUID
+	{- This will make the first commit to git, so ensure git is set up
+	 - properly to allow commits when running it. -}
+	ensureCommit $ do
+		Annex.Branch.create
+		describeUUID u =<< genDescription mdescription
+
+initialize' :: Annex ()
+initialize' = do
 	checkFifoSupport
 	checkCrippledFileSystem
 	unlessM isBare $
@@ -75,12 +87,6 @@ initialize mdescription = do
 			switchHEADBack
 		)
 	createInodeSentinalFile
-	u <- getUUID
-	{- This will make the first commit to git, so ensure git is set up
-	 - properly to allow commits when running it. -}
-	ensureCommit $ do
-		Annex.Branch.create
-		describeUUID u =<< genDescription mdescription
 
 uninitialize :: Annex ()
 uninitialize = do
diff --git a/Annex/UUID.hs b/Annex/UUID.hs
index 4e27450..5ed8876 100644
--- a/Annex/UUID.hs
+++ b/Annex/UUID.hs
@@ -21,6 +21,7 @@ module Annex.UUID (
 	gCryptNameSpace,
 	removeRepoUUID,
 	storeUUID,
+	storeUUIDIn,
 	setUUID,
 ) where
 
@@ -70,7 +71,7 @@ getRepoUUID r = do
   where
 	updatecache u = do
 		g <- gitRepo
-		when (g /= r) $ storeUUID cachekey u
+		when (g /= r) $ storeUUIDIn cachekey u
 	cachekey = remoteConfig r "uuid"
 
 removeRepoUUID :: Annex ()
@@ -84,10 +85,13 @@ getUncachedUUID = toUUID . Git.Config.get key ""
 {- Make sure that the repo has an annex.uuid setting. -}
 prepUUID :: Annex ()
 prepUUID = whenM ((==) NoUUID <$> getUUID) $
-	storeUUID configkey =<< liftIO genUUID
+	storeUUID =<< liftIO genUUID
 
-storeUUID :: ConfigKey -> UUID -> Annex ()
-storeUUID configfield = setConfig configfield . fromUUID
+storeUUID :: UUID -> Annex ()
+storeUUID = storeUUIDIn configkey
+
+storeUUIDIn :: ConfigKey -> UUID -> Annex ()
+storeUUIDIn configfield = setConfig configfield . fromUUID
 
 {- Only sets the configkey in the Repo; does not change .git/config -}
 setUUID :: Git.Repo -> UUID -> IO Git.Repo
diff --git a/Assistant/XMPP/Git.hs b/Assistant/XMPP/Git.hs
index ab34dce..36ada5c 100644
--- a/Assistant/XMPP/Git.hs
+++ b/Assistant/XMPP/Git.hs
@@ -74,7 +74,7 @@ makeXMPPGitRemote :: String -> JID -> UUID -> Assistant Bool
 makeXMPPGitRemote buddyname jid u = do
 	remote <- liftAnnex $ addRemote $
 		makeGitRemote buddyname $ gitXMPPLocation jid
-	liftAnnex $ storeUUID (remoteConfig (Remote.repo remote) "uuid") u
+	liftAnnex $ storeUUIDIn (remoteConfig (Remote.repo remote) "uuid") u
 	liftAnnex $ void remoteListRefresh
 	remote' <- liftAnnex $ fromMaybe (error "failed to add remote")
 		<$> Remote.byName (Just buddyname)
diff --git a/CmdLine/GitAnnex.hs b/CmdLine/GitAnnex.hs
index 7fdad4d..523c3f0 100644
--- a/CmdLine/GitAnnex.hs
+++ b/CmdLine/GitAnnex.hs
@@ -57,6 +57,7 @@ import qualified Command.Info
 import qualified Command.Status
 import qualified Command.Migrate
 import qualified Command.Uninit
+import qualified Command.Reinit
 import qualified Command.NumCopies
 import qualified Command.Trust
 import qualified Command.Untrust
@@ -125,6 +126,7 @@ cmds = concat
 	, Command.Reinject.def
 	, Command.Unannex.def
 	, Command.Uninit.def
+	, Command.Reinit.def
 	, Command.PreCommit.def
 	, Command.NumCopies.def
 	, Command.Trust.def
diff --git a/Command/Reinit.hs b/Command/Reinit.hs
new file mode 100644
index 0000000..0fc1e83
--- /dev/null
+++ b/Command/Reinit.hs
@@ -0,0 +1,38 @@
+{- git-annex command
+ -
+ - Copyright 2014 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Command.Reinit where
+
+import Common.Annex
+import Command
+import Annex.Init
+import Annex.UUID
+import Types.UUID
+import qualified Remote
+	
+def :: [Command]
+def = [dontCheck repoExists $
+	command "reinit" (paramUUID ++ " or " ++ paramDesc) seek SectionUtility ""]
+
+seek :: CommandSeek
+seek = withWords start
+
+start :: [String] -> CommandStart
+start ws = do
+	showStart "reinit" s
+	next $ perform s
+  where
+	s = unwords ws
+
+perform :: String -> CommandPerform
+perform s = do
+	u <- if isUUID s
+		then return $ toUUID s
+		else Remote.nameToUUID s
+	storeUUID u
+	initialize'
+	next $ return True
diff --git a/Types/UUID.hs b/Types/UUID.hs
index 8a304df..df38840 100644
--- a/Types/UUID.hs
+++ b/Types/UUID.hs
@@ -8,6 +8,8 @@
 module Types.UUID where
 
 import qualified Data.Map as M
+import qualified Data.UUID as U
+import Data.Maybe
 
 -- A UUID is either an arbitrary opaque string, or UUID info may be missing.
 data UUID = NoUUID | UUID String
@@ -21,4 +23,7 @@ toUUID :: String -> UUID
 toUUID [] = NoUUID
 toUUID s = UUID s
 
+isUUID :: String -> Bool
+isUUID = isJust . U.fromString
+
 type UUIDMap = M.Map UUID String
diff --git a/debian/changelog b/debian/changelog
index 08703d9..5fcec00 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -17,6 +17,10 @@ git-annex (5.20140413) UNRELEASED; urgency=medium
   * Avoid depending on shakespeare except for when building the webapp.
   * uninit: Avoid making unncessary copies of files.
   * info: Allow use in a repository where annex.uuid is not set.
+  * reinit: New command that can initialize a new reposotory using
+    the configuration of a previously known repository.
+    Useful if a repository got deleted and you want
+    to clone it back the way it was.
 
  -- Joey Hess <joeyh@debian.org>  Fri, 11 Apr 2014 21:33:35 -0400
 
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index d6f3d21..32680b3 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -845,6 +845,17 @@ subdirectories).
   repository, and remove all of git-annex's other data, leaving you with a

(Diff truncated)
poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index c6dbb37..a87a674 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 16 "Amazon S3 (done)" 12 "Amazon Glacier (done)" 9 "Box.com (done)" 71 "My phone (or MP3 player)" 25 "Tahoe-LAFS" 10 "OpenStack SWIFT" 33 "Google Drive"]]
+[[!poll open=yes 16 "Amazon S3 (done)" 12 "Amazon Glacier (done)" 9 "Box.com (done)" 72 "My phone (or MP3 player)" 25 "Tahoe-LAFS" 10 "OpenStack SWIFT" 33 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

Added a comment: Altering AWS credentials
diff --git a/doc/tips/using_Amazon_S3/comment_3_32acba030c2ad252e2f7027075e4303e._comment b/doc/tips/using_Amazon_S3/comment_3_32acba030c2ad252e2f7027075e4303e._comment
new file mode 100644
index 0000000..e83ade0
--- /dev/null
+++ b/doc/tips/using_Amazon_S3/comment_3_32acba030c2ad252e2f7027075e4303e._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="annexuser"
+ ip="64.71.7.82"
+ subject="Altering AWS credentials"
+ date="2014-04-15T21:59:43Z"
+ content="""
+If I revoke old AWS credentials and create new ones, how would I inform git-annex of the change to `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`?
+"""]]

diff --git a/doc/forum/Corrupt_Repository_Invalid_Object.mdwn b/doc/forum/Corrupt_Repository_Invalid_Object.mdwn
new file mode 100644
index 0000000..af6d8e3
--- /dev/null
+++ b/doc/forum/Corrupt_Repository_Invalid_Object.mdwn
@@ -0,0 +1,10 @@
+One of my repositories got corrupted. I am not exactly sure how it happened (was running a series of commands) but I think I accidentally ran regular mv instead of git mv. To fix it I deleted the moved file then checkout the original link however this did not fixed the problem. I ended up with a corrupted repo. Now running any command ends with the following error,
+
+    ga sync
+    (merging origin/git-annex origin/synced/git-annex into git-annex...)
+    (Recording state in git...)
+    error: invalid object 040000 6ad564920e3d78d31c9456f5be3869a0319f9f08 for'3fd/d44'                                                                                
+    fatal: git-write-tree: error building trees
+    git-annex: failed to read sha from git write-tree
+
+Was wondering how to fix this? I did run git fsck and git annex fsck but non fixed the problem.

Added a comment
diff --git a/doc/forum/Big_repository_vs._multiple_small/comment_2_656c62351502492d20e8490242e51169._comment b/doc/forum/Big_repository_vs._multiple_small/comment_2_656c62351502492d20e8490242e51169._comment
new file mode 100644
index 0000000..22fa765
--- /dev/null
+++ b/doc/forum/Big_repository_vs._multiple_small/comment_2_656c62351502492d20e8490242e51169._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="divB"
+ ip="128.12.90.218"
+ subject="comment 2"
+ date="2014-04-15T18:23:13Z"
+ content="""
+Thank you, that's a good point!
+
+Does this also mean that a repository in git(-annex) is \"all or nothing\"?
+
+For example, I cannot share/clone parts of it? Or define access rights within a repository?
+
+With SVN for example, I have a big repository \"university\" and it contains all stuff of projects/research. Each individual directory is only shared with the persons whom I worked together in this particular project. In short: In git, this should not be that way, right?
+"""]]

found a way to make uninit always fast
To do so, I slightly changed the behavior of unannex. Now in fast mode, it
only makes a hard link when the annexed file's link count is 1. This avoids
unannexing 2 files with the same content in fast mode from hard linking
them together. (One will end up hard linked to the annex, which the docs
warn about.)
With that change, uninit can simply always run unannex in fast mode. Since
.git/annex/objects is being blown away anyway, there's no worry in this
case about a hard link pointing into it causing an annexed object to be
modified.
diff --git a/Command/Unannex.hs b/Command/Unannex.hs
index 3da7c2a..ca9788d 100644
--- a/Command/Unannex.hs
+++ b/Command/Unannex.hs
@@ -75,7 +75,16 @@ cleanupIndirect :: FilePath -> Key -> CommandCleanup
 cleanupIndirect file key = do
 	src <- calcRepo $ gitAnnexLocation key
 	ifM (Annex.getState Annex.fast)
-		( hardlinkfrom src
+		( do
+			-- Only make a hard link if the annexed file does not
+			-- already have other hard links pointing at it.
+			-- This avoids unannexing (and uninit) ending up
+			-- hard linking files together, which would be
+			-- surprising.
+			s <- liftIO $ getFileStatus src
+			if linkCount s > 1
+				then copyfrom src
+				else hardlinkfrom src
 		, copyfrom src
 		)
   where
diff --git a/Command/Uninit.hs b/Command/Uninit.hs
index 5b2adf0..dccf4a6 100644
--- a/Command/Uninit.hs
+++ b/Command/Uninit.hs
@@ -8,6 +8,7 @@
 module Command.Uninit where
 
 import Common.Annex
+import qualified Annex
 import Command
 import qualified Git
 import qualified Git.Command
@@ -37,6 +38,7 @@ check = do
 seek :: CommandSeek
 seek ps = do
 	withFilesNotInGit False (whenAnnexed startCheckIncomplete) ps
+	Annex.changeState $ \s -> s { Annex.fast = True }
 	withFilesInGit (whenAnnexed Command.Unannex.start) ps
 	finish
 
diff --git a/debian/changelog b/debian/changelog
index e886f14..31226e4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -15,6 +15,7 @@ git-annex (5.20140413) UNRELEASED; urgency=medium
     connections.
   * Improve handling of monthly/yearly scheduling.
   * Avoid depending on shakespeare except for when building the webapp.
+  * uninit: Avoid making unncessary copies of files.
 
  -- Joey Hess <joeyh@debian.org>  Fri, 11 Apr 2014 21:33:35 -0400
 
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 9d896c6..d6f3d21 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -845,10 +845,6 @@ subdirectories).
   repository, and remove all of git-annex's other data, leaving you with a
   git repository plus the previously annexed files.
 
-  Normally this does a slow copy of every file. In `--fast` mode, this copy
-  is avoided, but if two files in the repository have the same content,
-  they will end up hard linked together.
-
 # PLUMBING COMMANDS
 
 * `pre-commit [path ...]`

document uninit --fast and also why it's not the default
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index d6f3d21..9d896c6 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -845,6 +845,10 @@ subdirectories).
   repository, and remove all of git-annex's other data, leaving you with a
   git repository plus the previously annexed files.
 
+  Normally this does a slow copy of every file. In `--fast` mode, this copy
+  is avoided, but if two files in the repository have the same content,
+  they will end up hard linked together.
+
 # PLUMBING COMMANDS
 
 * `pre-commit [path ...]`

Added a comment
diff --git a/doc/forum/best_practices_for_importing_photos__63__/comment_1_37f0ae4b552ec2a4a144ddcdc17c8453._comment b/doc/forum/best_practices_for_importing_photos__63__/comment_1_37f0ae4b552ec2a4a144ddcdc17c8453._comment
new file mode 100644
index 0000000..3d17874
--- /dev/null
+++ b/doc/forum/best_practices_for_importing_photos__63__/comment_1_37f0ae4b552ec2a4a144ddcdc17c8453._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="Xyem"
+ ip="178.79.137.64"
+ subject="comment 1"
+ date="2014-04-15T14:25:04Z"
+ content="""
+git-annex's metadata and views made me stop hopping between programs (digikam, tagsistant etc.) to organise my photos (I had even just started working on my own FUSE tagging filesystem which was effectively going to be tagsistant, but with a git-annex'y backend).
+
+As usual, my method is probably a little odd :)
+
+Photos are 'git import'ed into a $(uuidgen) directory (so no worries about filename collisions) and tagged with media=Photograph and tag=untagged. Then I go through them and add relevant tags (one of which is \"xbmc\", no prizes for guessing how that works with the views :]) and move them into a more appropriate directory structure, using gqview and its \"sort manager\". This is really nice and fast, due to it only copying/moving symlinks!
+
+One thing I'm considering doing it putting a shim between git-annex and gqview, so that it generates entries in the sort manager which are appropriate for the current view. So, for example, if the view is location=*, the sort manager would have:
+
+    location=Malta
+    location=York
+
+While it wouldn't get updated if I create new tags (by creating directories in the view), it would save a lot of time creating them every time the view changes.
+"""]]

Added a comment: great job on that plugin!
diff --git a/doc/tips/flickrannex/comment_14_c728f10074d194efa8b2c60e97d275e7._comment b/doc/tips/flickrannex/comment_14_c728f10074d194efa8b2c60e97d275e7._comment
new file mode 100644
index 0000000..f625d6b
--- /dev/null
+++ b/doc/tips/flickrannex/comment_14_c728f10074d194efa8b2c60e97d275e7._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://id.koumbit.net/anarcat"
+ ip="72.0.72.144"
+ subject="great job on that plugin!"
+ date="2014-04-15T04:47:17Z"
+ content="""
+it's pretty awesome to have 1TB of free storage like that out there... but for storing photos, it could be improved - I filed a few bugs on the github repo here:
+
+https://github.com/TobiasTheViking/flickrannex/issues/created_by/anarcat?state=open
+
+thanks!
+"""]]

diff --git a/doc/bugs/fatal:_Out_of_memory__63___mmap_failed:_No_error.mdwn b/doc/bugs/fatal:_Out_of_memory__63___mmap_failed:_No_error.mdwn
new file mode 100644
index 0000000..f9a619a
--- /dev/null
+++ b/doc/bugs/fatal:_Out_of_memory__63___mmap_failed:_No_error.mdwn
@@ -0,0 +1,30 @@
+### Please describe the problem.
+
+When adding files, the error
+
+ fatal: Out of memory? mmap failed: No error
+
+appears 
+
+
+### What steps will reproduce the problem?
+
+In Windows, I have a directory with 8GB and 333.820 files (of course, in different directory, the big one is probably the Android SDK).
+
+### What version of git-annex are you using? On what operating system?
+
+Windows 8.
+
+ $ git annex version
+ git-annex version: 5.20140411-gda795e0
+ build flags: Assistant Webapp Webapp-secure Pairing Testsuite S3 WebDAV DNS Feeds Quvi TDFA CryptoHash
+ key/value backends: SHA256E SHA1E SHA512E SHA224E SHA384E SKEIN256E SKEIN512E SHA256 SHA1 SHA512 SHA224 SHA384 SKEIN256 SKEIN512 WORM URL
+ remote types: git gcrypt S3 bup directory rsync web webdav tahoe glacier hook external
+ local repository version: 5
+ supported repository version: 5
+ upgrade supported from repository versions: 2 3 4
+
+
+### Please provide any additional information below.
+
+

devblog
diff --git a/doc/devblog/day_153__remotedaemon_has_landed.mdwn b/doc/devblog/day_153__remotedaemon_has_landed.mdwn
new file mode 100644
index 0000000..5033b32
--- /dev/null
+++ b/doc/devblog/day_153__remotedaemon_has_landed.mdwn
@@ -0,0 +1,10 @@
+After fixing a few bugs in the `remotecontrol` branch, It's landed in
+`master`. Try a daily build today, and see if the assistant can keep in
+sync using nothing more than a remote ssh repository!
+
+So, now all the groundwork for telehash is laid too. I only need a
+telehash library to start developing on top of. Development on telehash-c
+is continuing, but I'm more excited that
+[htelehash](https://github.com/alanz/htelehash/tree/v2) 
+has been revived and is being updated to the v2 protocol, seemingly quite
+quickly.

Added a comment
diff --git a/doc/forum/Starting_assistant_from_CLI/comment_2_76c34c00cf2065809b15a594023a688b._comment b/doc/forum/Starting_assistant_from_CLI/comment_2_76c34c00cf2065809b15a594023a688b._comment
new file mode 100644
index 0000000..d0ce4b2
--- /dev/null
+++ b/doc/forum/Starting_assistant_from_CLI/comment_2_76c34c00cf2065809b15a594023a688b._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawlqL3QbH6hrzf4XT-OW5IcMj6zSrMWl2dg"
+ nickname="Michel"
+ subject="comment 2"
+ date="2014-04-14T22:45:23Z"
+ content="""
+Unfortunately, no, I tried this and many other variants, (I tried again just now, to be sure, and I still get the \"git-annex: Not in a git repository.\" message.
+
+Thanks for trying to help. It is very much appreciated.
+
+"""]]

diff --git a/doc/forum/best_practices_for_importing_photos__63__.mdwn b/doc/forum/best_practices_for_importing_photos__63__.mdwn
new file mode 100644
index 0000000..2f57f3b
--- /dev/null
+++ b/doc/forum/best_practices_for_importing_photos__63__.mdwn
@@ -0,0 +1,13 @@
+What are everyone's tips for importing photos to make best use of metadata and views?
+
+Let's assume there's no need to be compatible with a photo manager app, but we may be importing lots of duplicates, and while content deduplication is great, I'd like to avoid naming problems too.
+
+Do you bother to rename your photos?
+
+Do you use EXIF metadata as git-annex metadata? Selectively or wholesale, with all the redundant tags in EXIF?
+
+If you do use a photo manager app, do you need to do anything special to make that work?
+
+Thanks for your responses everyone!
+
+-mike

fix RESUME
diff --git a/RemoteDaemon/Core.hs b/RemoteDaemon/Core.hs
index b3cfe67..0be9c93 100644
--- a/RemoteDaemon/Core.hs
+++ b/RemoteDaemon/Core.hs
@@ -76,10 +76,10 @@ runController ichan ochan = do
 				-- ssh remotes, it's only done once)
 				liftAnnex h forceSshCleanup
 				broadcast LOSTNET m
-				go h True M.empty
+				go h True m
 			PAUSE -> do
 				broadcast STOP m
-				go h True M.empty
+				go h True m
 			RESUME -> do
 				when paused $
 					startrunning m
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index fbc2885..56afa40 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -105,7 +105,7 @@ the webapp.
 
 * `RESUME`
 
-  Undoes PAUSE or DISCONNECTED.  
+  Undoes PAUSE or LOSTNET.  
   Start back up network connections.
 
 * `CHANGED ref ...`

improve desc
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 03e05d9..d6f3d21 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -924,7 +924,7 @@ subdirectories).
 
 * `remotedaemon`
 
-  Detects when remotes have changed and fetches from them.
+  Detects when network remotes have received git pushes and fetches from them.
 
 * `xmppgit`
 

Added a comment
diff --git a/doc/forum/Starting_assistant_from_CLI/comment_1_afd51ddb0f1bb3cac528e1d96829ef83._comment b/doc/forum/Starting_assistant_from_CLI/comment_1_afd51ddb0f1bb3cac528e1d96829ef83._comment
new file mode 100644
index 0000000..05c7a12
--- /dev/null
+++ b/doc/forum/Starting_assistant_from_CLI/comment_1_afd51ddb0f1bb3cac528e1d96829ef83._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="https://me.yahoo.com/a/FHnTlSBo1eCGJRwueeKeB6.RCaPbGMPr5jxx8A--#ce0d8"
+ nickname="Hamza"
+ subject="comment 1"
+ date="2014-04-14T15:35:17Z"
+ content="""
+running,
+
+    git annex webapp
+
+should launch the web app.
+"""]]

Added a comment
diff --git a/doc/forum/Big_repository_vs._multiple_small/comment_1_8e21ee3c674ef6e595bdab53dd5c2356._comment b/doc/forum/Big_repository_vs._multiple_small/comment_1_8e21ee3c674ef6e595bdab53dd5c2356._comment
new file mode 100644
index 0000000..707a1cc
--- /dev/null
+++ b/doc/forum/Big_repository_vs._multiple_small/comment_1_8e21ee3c674ef6e595bdab53dd5c2356._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://me.yahoo.com/a/FHnTlSBo1eCGJRwueeKeB6.RCaPbGMPr5jxx8A--#ce0d8"
+ nickname="Hamza"
+ subject="comment 1"
+ date="2014-04-14T15:32:34Z"
+ content="""
+In my setup I have one repository for each category (photos documents videos) it is faster then single giant repository plus it makes sharing with other people easier since you can let people clone one category at a time.
+"""]]

Added a comment
diff --git a/doc/forum/taskwarrior/comment_2_4b3d70501763f6d36c927ae37bbd33c2._comment b/doc/forum/taskwarrior/comment_2_4b3d70501763f6d36c927ae37bbd33c2._comment
new file mode 100644
index 0000000..ec6bcb9
--- /dev/null
+++ b/doc/forum/taskwarrior/comment_2_4b3d70501763f6d36c927ae37bbd33c2._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://me.yahoo.com/a/FHnTlSBo1eCGJRwueeKeB6.RCaPbGMPr5jxx8A--#ce0d8"
+ nickname="Hamza"
+ subject="comment 2"
+ date="2014-04-14T15:27:48Z"
+ content="""
+Using direct mode would replace symlinks with actual files.
+"""]]

its "approxlackingcopies", not "roughlylackingcopies"
diff --git a/doc/preferred_content/standard_groups.mdwn b/doc/preferred_content/standard_groups.mdwn
index dd73b66..2a62416 100644
--- a/doc/preferred_content/standard_groups.mdwn
+++ b/doc/preferred_content/standard_groups.mdwn
@@ -13,7 +13,7 @@ any repository that can will back it up.)
 All content is wanted, unless it's for a file in a "archive" directory,
 which has reached an archive repository, or is unused.
 
-`(((exclude=*/archive/* and exclude=archive/*) or (not (copies=archive:1 or copies=smallarchive:1))) and not unused) or roughlylackingcopies=1`
+`(((exclude=*/archive/* and exclude=archive/*) or (not (copies=archive:1 or copies=smallarchive:1))) and not unused) or approxlackingcopies=1`
 
 ### transfer
 

fix typo
diff --git a/doc/devblog/day_152__more_ssh_connection_caching.mdwn b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
index b55525d..ad472b5 100644
--- a/doc/devblog/day_152__more_ssh_connection_caching.mdwn
+++ b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
@@ -10,7 +10,7 @@ when git invokes git-annex as ssh, it runs ssh with the connection caching
 parameters.
 
 Also, improved the network-manager and wicd code, so it detects when a
-connection has gone down. That propigates through to the remote-daemon,
+connection has gone down. That propagates through to the remote-daemon,
 which closes all ssh connections. I need to also find out how to detect
 network connections/disconnections on OSX..
 

Added a comment: auto conflict resolution master branch
diff --git a/doc/automatic_conflict_resolution/comment_6_8a0860fee88f5954918305f055a39d8d._comment b/doc/automatic_conflict_resolution/comment_6_8a0860fee88f5954918305f055a39d8d._comment
new file mode 100644
index 0000000..4e9493d
--- /dev/null
+++ b/doc/automatic_conflict_resolution/comment_6_8a0860fee88f5954918305f055a39d8d._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawn3p4i4lk_zMilvjnJ9sS6g2nerpgz0Fjc"
+ nickname="Matthias"
+ subject="auto conflict resolution master branch"
+ date="2014-04-13T17:48:19Z"
+ content="""
+@joeyh: This must be a misunderstanding of what I want. I use version 5.20140320. I can't find a workflow where \"git annex merge\" changes my master branch, it only updates the git-annex branch.
+
+Thinking again of it after some time, I am basically fine with \"git annex sync\". The only thing I am uncomfortable with is that the automatic merge is pushed without review.
+"""]]

diff --git a/doc/forum/Big_repository_vs._multiple_small.mdwn b/doc/forum/Big_repository_vs._multiple_small.mdwn
new file mode 100644
index 0000000..c77dd02
--- /dev/null
+++ b/doc/forum/Big_repository_vs._multiple_small.mdwn
@@ -0,0 +1,8 @@
+I am new to git (but extensively used SVN).
+
+In SVN I could have a big fat repository but only check out sub-trees is it.
+Is that also common in git(-annex) / recommended?
+
+E.g., should I create a big-fat repos with all data I have (personal data, music, videos, ...) and check out only the appropriate subtress or create a repository for each purpose? E.g., one for Fotos, Music, OnTheGoData, ebooks, ...
+
+What happens if I have a git-annex repository checked out at my laptop (say, d:\Files) and within it, check out another one (e.g. d:\Files\Library)?

Fixed Shebang in script and typo.
diff --git a/doc/tips/file_manager_integration.mdwn b/doc/tips/file_manager_integration.mdwn
index 1a1a557..3fea3e9 100644
--- a/doc/tips/file_manager_integration.mdwn
+++ b/doc/tips/file_manager_integration.mdwn
@@ -91,10 +91,10 @@ Edit this page and add instructions!
 If your file manager can run a command on a file, it should be easy to
 integrate git-annex with it. A simple script will suffice:
 
-	#!/bun/sh
+	#!/bin/sh
 	git-annex get --notify-start --notify-finish -- "$@"
 
 The --notify-start and --notify-stop options make git-annex display a
 desktop notification. This is useful to give the user an indication that
 their action took effect. Desktop notifications are currently only
-implenented for Linux.
+implemented for Linux.

make links to internal pages instead of only github to allow cross-finding them all
diff --git a/doc/users/tobiastheviking.mdwn b/doc/users/tobiastheviking.mdwn
index 0629e34..31398da 100644
--- a/doc/users/tobiastheviking.mdwn
+++ b/doc/users/tobiastheviking.mdwn
@@ -2,19 +2,12 @@ Tobias Ussing
 
 See:
 
-[[https://github.com/TobiasTheViking/flickrannex/]]
-
-[[https://github.com/TobiasTheViking/imapannex]]
-
-[[https://github.com/TobiasTheViking/dropboxannex]]
-
-[[https://github.com/TobiasTheViking/skydriveannex]]
-
-[[https://github.com/TobiasTheViking/googledriveannex]]
-
-[[https://github.com/TobiasTheViking/owncloudannex]]
-
-[[https://github.com/TobiasTheViking/megaannex]]
-
-[[http://git-annex.branchable.com/forum/nntp__47__usenet_special_remote/]]
+* [[tips/flickrannex]] - [[https://github.com/TobiasTheViking/flickrannex/]]
+* [[tips/imapannex]] - [[https://github.com/TobiasTheViking/imapannex]]
+* [[tips/dropboxannex]] - [[https://github.com/TobiasTheViking/dropboxannex]]
+* [[tips/skydriveannex]] - [[https://github.com/TobiasTheViking/skydriveannex]]
+* [[tips/googledriveannex]] - [[https://github.com/TobiasTheViking/googledriveannex]]
+* [[tips/owncloudannex]] - [[https://github.com/TobiasTheViking/owncloudannex]]
+* [[tips/megaannex]] - [[https://github.com/TobiasTheViking/megaannex]]
+* [[forum/nntp__47__usenet_special_remote/]]
 

diff --git a/doc/forum/Starting_assistant_from_CLI.mdwn b/doc/forum/Starting_assistant_from_CLI.mdwn
new file mode 100644
index 0000000..8a4bc3d
--- /dev/null
+++ b/doc/forum/Starting_assistant_from_CLI.mdwn
@@ -0,0 +1,9 @@
+I am unable to start the git-annex assistant/webapp.
+
+I use OpenBox as desktop manager and the assistant/webapp is not available through the menu.
+
+Trying to use the CLI, all my attempts fail with a message saying that it(?) is not a git repository!? Since the video show that on first start the assistant/webapp allows a choice of a directory and then creates it, I am not sure as to what git initialized directory does the assistant/webapp requires in this instance. And I also guess that means invoking the webapp from that directory rather than from the directory that contains the standalone git-annex.
+
+Any help would be appreciated as git-annex really seems to be the app I am looking for.  :)
+
+Thanks

day's sponsor
diff --git a/doc/devblog/day_152__more_ssh_connection_caching.mdwn b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
index 8edb885..b55525d 100644
--- a/doc/devblog/day_152__more_ssh_connection_caching.mdwn
+++ b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
@@ -31,3 +31,7 @@ new `oneMonthPast` old = fromGregorian y (m+1) d <= new
   where
         (y,m,d) = toGregorian old
 """]]
+
+-------
+
+Today's work was sponsored by Asbjørn Sloth Tønnesen.

day's sponsor
diff --git a/doc/devblog/day_152__more_ssh_connection_caching.mdwn b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
index 8edb885..b55525d 100644
--- a/doc/devblog/day_152__more_ssh_connection_caching.mdwn
+++ b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
@@ -31,3 +31,7 @@ new `oneMonthPast` old = fromGregorian y (m+1) d <= new
   where
         (y,m,d) = toGregorian old
 """]]
+
+-------
+
+Today's work was sponsored by Asbjørn Sloth Tønnesen.

devblog
diff --git a/doc/devblog/day_152__more_ssh_connection_caching.mdwn b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
new file mode 100644
index 0000000..8edb885
--- /dev/null
+++ b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
@@ -0,0 +1,33 @@
+Made ssh connection caching be used in several more places. `git annex
+sync` will use it when pushing/pulling to a remote, as will the assistant.
+And `git-annex remotedaemon` also uses connection caching. So, when
+a push lands on a ssh remote, the assistant will immediately notice it, and
+pull down the change over the same TCP connection used for the
+notifications.
+
+This was a bit of a pain to do. Had to set `GIT_SSH=git-annex` and then
+when git invokes git-annex as ssh, it runs ssh with the connection caching
+parameters.
+
+Also, improved the network-manager and wicd code, so it detects when a
+connection has gone down. That propigates through to the remote-daemon,
+which closes all ssh connections. I need to also find out how to detect
+network connections/disconnections on OSX..
+
+Otherwise, the remote-control branch seems ready to be merged. But I want
+to test it for a while first.
+
+----
+
+Followed up on yesterday's bug with writing some test cases for
+Utility.Scheduled, which led to some more bug fixes. Luckily nothing
+I need to rush out a release over. In the end, the code got a lot
+simpler and clearer.
+
+[[!format haskell """
+-- Check if the new Day occurs one month or more past the old Day.
+oneMonthPast :: Day -> Day -> Bool
+new `oneMonthPast` old = fromGregorian y (m+1) d <= new
+  where
+        (y,m,d) = toGregorian old
+"""]]

devblog
diff --git a/doc/devblog/day_152__more_ssh_connection_caching.mdwn b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
new file mode 100644
index 0000000..8edb885
--- /dev/null
+++ b/doc/devblog/day_152__more_ssh_connection_caching.mdwn
@@ -0,0 +1,33 @@
+Made ssh connection caching be used in several more places. `git annex
+sync` will use it when pushing/pulling to a remote, as will the assistant.
+And `git-annex remotedaemon` also uses connection caching. So, when
+a push lands on a ssh remote, the assistant will immediately notice it, and
+pull down the change over the same TCP connection used for the
+notifications.
+
+This was a bit of a pain to do. Had to set `GIT_SSH=git-annex` and then
+when git invokes git-annex as ssh, it runs ssh with the connection caching
+parameters.
+
+Also, improved the network-manager and wicd code, so it detects when a
+connection has gone down. That propigates through to the remote-daemon,
+which closes all ssh connections. I need to also find out how to detect
+network connections/disconnections on OSX..
+
+Otherwise, the remote-control branch seems ready to be merged. But I want
+to test it for a while first.
+
+----
+
+Followed up on yesterday's bug with writing some test cases for
+Utility.Scheduled, which led to some more bug fixes. Luckily nothing
+I need to rush out a release over. In the end, the code got a lot
+simpler and clearer.
+
+[[!format haskell """
+-- Check if the new Day occurs one month or more past the old Day.
+oneMonthPast :: Day -> Day -> Bool
+new `oneMonthPast` old = fromGregorian y (m+1) d <= new
+  where
+        (y,m,d) = toGregorian old
+"""]]

ssh transport seems ready, needs testing
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index 7ab428e..fbc2885 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -162,26 +162,7 @@ over stdio to inform when refs on the remote have changed.
 
 No pushing is done for CHANGED, since git handles ssh natively.
 
-TODO:
-
-* Remote system might not be available. Find a smart way to detect it,
-  ideally w/o generating network traffic. One way might be to check
-  if the ssh connection caching control socket exists, for example.
-* Now that ssh connection caching is enabled for git push/pull in sync,
-  there's the possibility that a stale ssh connection may linger when 
-  changing network connections, and so attempts to use it will stall.  
-  (This was already a potential issue with transfers, which already
-  used the caching.)  
-
-  One option is ssh's ServerAliveCountMax, which will make a dead
-  ssh connection disconnect after approx 45 seconds, per ssh manual.
-  It would need to be enabled by setting ServerAliveInterval=15.
-  And this would add network traffic..
-
-  Another option is to disable all cached connections when the network
-  connection changes. This would handle *most* cases. The case
-  not handled is eg, my dialup ppp box getting a new public IP address,
-  which my laptop won't notice. **done**
+TODO: test!
 
 ## telehash 
 

detect wicd network disconnection events
diff --git a/Assistant/Threads/NetWatcher.hs b/Assistant/Threads/NetWatcher.hs
index c1115f6..9dd6178 100644
--- a/Assistant/Threads/NetWatcher.hs
+++ b/Assistant/Threads/NetWatcher.hs
@@ -130,18 +130,36 @@ listenNMConnections client setconnected =
 			setconnected True
 		| otherwise = noop
 
-{- Listens for Wicd connections (not currently disconnections). -}
+{- Listens for Wicd connections and disconnections.
+ -
+ - Connection example:
+ -   ConnectResultsSent:
+ -     Variant "success"
+ -
+ - Diconnection example:
+ -   StatusChanged
+ -     [Variant 0, Variant [Varient ""]]
+ -}
 listenWicdConnections :: Client -> (Bool -> IO ()) -> IO ()
-listenWicdConnections client callback =
-	listen client matcher $ \event ->
+listenWicdConnections client setconnected = do
+	listen client connmatcher $ \event ->
 		when (any (== wicd_success) (signalBody event)) $
-			callback False >> callback True
+			setconnected True
+	listen client statusmatcher $ \event -> handle (signalBody event)
   where
-	matcher = matchAny
+	connmatcher = matchAny
 		{ matchInterface = Just "org.wicd.daemon"
 		, matchMember = Just "ConnectResultsSent"
 		}
+	statusmatcher = matchAny
+		{ matchInterface = Just "org.wicd.daemon"
+		, matchMember = Just "StatusChanged"
+		}
 	wicd_success = toVariant ("success" :: String)
+	wicd_disconnected = toVariant [toVariant ("" :: String)]
+	handle status
+		| any (== wicd_disconnected) status = setconnected False
+		| otherwise = noop
 
 #endif
 
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index a0e2419..7ab428e 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -164,9 +164,6 @@ No pushing is done for CHANGED, since git handles ssh natively.
 
 TODO:
 
-* For wicd, the NetWatcher does not detect network loss, only network gain.
-  So PAUSE is only sent when a new network is detected, followed
-  immediately by RESUME. This was already fixed for networkmanager.
 * Remote system might not be available. Find a smart way to detect it,
   ideally w/o generating network traffic. One way might be to check
   if the ssh connection caching control socket exists, for example.

NetWatcher: detect when networkmanager has lost network connection
This is a better approach to finding both when NM has lost a network
connection, and when a new network connection is made by NM.
Tested with network-manager 0.9.8.8.
This commit was sponsored by Cedric Staub.
diff --git a/Assistant/Threads/NetWatcher.hs b/Assistant/Threads/NetWatcher.hs
index 0ff605e..c1115f6 100644
--- a/Assistant/Threads/NetWatcher.hs
+++ b/Assistant/Threads/NetWatcher.hs
@@ -22,7 +22,6 @@ import Utility.NotificationBroadcaster
 import Utility.DBus
 import DBus.Client
 import DBus
-import Data.Word (Word32)
 import Assistant.NetMessager
 #else
 #ifdef linux_HOST_OS
@@ -63,15 +62,19 @@ dbusThread = do
   where
 	go client = ifM (checkNetMonitor client)
 		( do
-			listenNMConnections client <~> handleconn
-			listenWicdConnections client <~> handleconn
+			callback <- asIO1 connchange
+			liftIO $ do
+				listenNMConnections client callback
+				listenWicdConnections client callback
 		, do
 			liftAnnex $
 				warning "No known network monitor available through dbus; falling back to polling"
 		)
-	handleconn = do
-		debug ["detected network connection"]
+	connchange False = do
+		debug ["detected network disconnection"]
 		sendRemoteControl LOSTNET
+	connchange True = do
+		debug ["detected network connection"]
 		notifyNetMessagerRestart
 		handleConnection
 		sendRemoteControl RESUME
@@ -99,31 +102,40 @@ checkNetMonitor client = do
 	networkmanager = "org.freedesktop.NetworkManager"
 	wicd = "org.wicd.daemon"
 
-{- Listens for new NetworkManager connections. -}
-listenNMConnections :: Client -> IO () -> IO ()
-listenNMConnections client callback =
-	listen client matcher $ \event ->
-		when (Just True == anyM activeconnection (signalBody event)) $
-			callback
+{- Listens for NetworkManager connections and diconnections.
+ -
+ - Connection example (once fully connected):
+ - [Variant {"ActivatingConnection": Variant (ObjectPath "/"), "PrimaryConnection": Variant (ObjectPath "/org/freedesktop/NetworkManager/ActiveConnection/34"), "State": Variant 70}]
+ -
+ - Disconnection example:
+ - [Variant {"ActiveConnections": Variant []}]
+ -}
+listenNMConnections :: Client -> (Bool -> IO ()) -> IO ()
+listenNMConnections client setconnected =
+	listen client matcher $ \event -> mapM_ handle
+		(map dictionaryItems $ mapMaybe fromVariant $ signalBody event)
   where
 	matcher = matchAny
-		{ matchInterface = Just "org.freedesktop.NetworkManager.Connection.Active"
+		{ matchInterface = Just "org.freedesktop.NetworkManager"
 		, matchMember = Just "PropertiesChanged"
 		}
-	nm_connection_activated = toVariant (2 :: Word32)
-	nm_state_key = toVariant ("State" :: String)
-	activeconnection v = do
-		m <- fromVariant v
-		vstate <- lookup nm_state_key $ dictionaryItems m
-		state <- fromVariant vstate
-		return $ state == nm_connection_activated
+	nm_active_connections_key = toVariant ("ActiveConnections" :: String)
+	nm_activatingconnection_key = toVariant ("ActivatingConnection" :: String)
+	noconnections = Just $ toVariant $ toVariant ([] :: [ObjectPath])
+	rootconnection = Just $ toVariant $ toVariant $ objectPath_ "/"
+	handle m
+		| lookup nm_active_connections_key m == noconnections =
+			setconnected False
+		| lookup nm_activatingconnection_key m == rootconnection =
+			setconnected True
+		| otherwise = noop
 
-{- Listens for new Wicd connections. -}
-listenWicdConnections :: Client -> IO () -> IO ()
+{- Listens for Wicd connections (not currently disconnections). -}
+listenWicdConnections :: Client -> (Bool -> IO ()) -> IO ()
 listenWicdConnections client callback =
 	listen client matcher $ \event ->
 		when (any (== wicd_success) (signalBody event)) $
-			callback
+			callback False >> callback True
   where
 	matcher = matchAny
 		{ matchInterface = Just "org.wicd.daemon"
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index a3d07ea..a0e2419 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -164,9 +164,9 @@ No pushing is done for CHANGED, since git handles ssh natively.
 
 TODO:
 
-* The NetWatcher does not detect network loss, only network gain,
-  so PAUSE is only sent when a new network is detected, followed
-  immediately by RESUME.
+* For wicd, the NetWatcher does not detect network loss, only network gain.
+  So PAUSE is only sent when a new network is detected, followed
+  immediately by RESUME. This was already fixed for networkmanager.
 * Remote system might not be available. Find a smart way to detect it,
   ideally w/o generating network traffic. One way might be to check
   if the ssh connection caching control socket exists, for example.

remotedaemon: When network connection is lost, close all cached ssh connections.
This commit was sponsored by Cedric Staub.
diff --git a/Annex/Ssh.hs b/Annex/Ssh.hs
index fab25c4..06e3ac4 100644
--- a/Annex/Ssh.hs
+++ b/Annex/Ssh.hs
@@ -11,6 +11,7 @@ module Annex.Ssh (
 	sshCachingOptions,
 	sshCacheDir,
 	sshReadPort,
+	forceSshCleanup,
 	sshCachingEnv,
 	sshCachingTo,
 	inRepoWithSshCachingTo,
@@ -124,21 +125,27 @@ prepSocket socketfile = do
 	liftIO $ createDirectoryIfMissing True $ parentDir socketfile
 	lockFile $ socket2lock socketfile
 
-{- Stop any unused ssh processes. -}
+enumSocketFiles :: Annex [FilePath]
+enumSocketFiles = go =<< sshCacheDir
+  where
+	go Nothing = return []
+	go (Just dir) = liftIO $ filter (not . isLock)
+		<$> catchDefaultIO [] (dirContents dir)
+
+{- Stop any unused ssh connection caching processes. -}
 sshCleanup :: Annex ()
-sshCleanup = go =<< sshCacheDir
+sshCleanup = mapM_ cleanup =<< enumSocketFiles
   where
-	go Nothing = noop
-	go (Just dir) = do
-		sockets <- liftIO $ filter (not . isLock)
-			<$> catchDefaultIO [] (dirContents dir)
-		forM_ sockets cleanup
 	cleanup socketfile = do
 #ifndef mingw32_HOST_OS
 		-- Drop any shared lock we have, and take an
 		-- exclusive lock, without blocking. If the lock
 		-- succeeds, nothing is using this ssh, and it can
 		-- be stopped.
+		--
+		-- After ssh is stopped cannot remove the lock file;
+		-- other processes may be waiting on our exclusive
+		-- lock to use it.
 		let lockfile = socket2lock socketfile
 		unlockFile lockfile
 		mode <- annexFileMode
@@ -148,24 +155,28 @@ sshCleanup = go =<< sshCacheDir
 			setLock fd (WriteLock, AbsoluteSeek, 0, 0)
 		case v of
 			Left _ -> noop
-			Right _ -> stopssh socketfile
+			Right _ -> forceStopSsh socketfile
 		liftIO $ closeFd fd
 #else
-		stopssh socketfile
+		forceStopSsh socketfile
 #endif
-	stopssh socketfile = do
-		let (dir, base) = splitFileName socketfile
-		let params = sshConnectionCachingParams base
-		-- "ssh -O stop" is noisy on stderr even with -q
-		void $ liftIO $ catchMaybeIO $
-			withQuietOutput createProcessSuccess $
-				(proc "ssh" $ toCommand $
-					[ Params "-O stop"
-					] ++ params ++ [Param "localhost"])
-					{ cwd = Just dir }
-		liftIO $ nukeFile socketfile
-		-- Cannot remove the lock file; other processes may
-		-- be waiting on our exclusive lock to use it.
+
+{- Stop all ssh connection caching processes, even when they're in use. -}
+forceSshCleanup :: Annex ()
+forceSshCleanup = mapM_ forceStopSsh =<< enumSocketFiles
+
+forceStopSsh :: FilePath -> Annex ()
+forceStopSsh socketfile = do
+	let (dir, base) = splitFileName socketfile
+	let params = sshConnectionCachingParams base
+	-- "ssh -O stop" is noisy on stderr even with -q
+	void $ liftIO $ catchMaybeIO $
+		withQuietOutput createProcessSuccess $
+			(proc "ssh" $ toCommand $
+				[ Params "-O stop"
+				] ++ params ++ [Param "localhost"])
+				{ cwd = Just dir }
+	liftIO $ nukeFile socketfile
 
 {- This needs to be as short as possible, due to limitations on the length
  - of the path to a socket file. At the same time, it needs to be unique
diff --git a/Assistant/Threads/NetWatcher.hs b/Assistant/Threads/NetWatcher.hs
index 912893b..0ff605e 100644
--- a/Assistant/Threads/NetWatcher.hs
+++ b/Assistant/Threads/NetWatcher.hs
@@ -71,7 +71,7 @@ dbusThread = do
 		)
 	handleconn = do
 		debug ["detected network connection"]
-		sendRemoteControl PAUSE
+		sendRemoteControl LOSTNET
 		notifyNetMessagerRestart
 		handleConnection
 		sendRemoteControl RESUME
diff --git a/RemoteDaemon/Core.hs b/RemoteDaemon/Core.hs
index 0c29371..b3cfe67 100644
--- a/RemoteDaemon/Core.hs
+++ b/RemoteDaemon/Core.hs
@@ -18,6 +18,7 @@ import qualified Git.Types as Git
 import qualified Git.CurrentRepo
 import Utility.SimpleProtocol
 import Config
+import Annex.Ssh
 
 import Control.Concurrent.Async
 import Control.Concurrent
@@ -65,12 +66,19 @@ runController ichan ochan = do
 				let common = M.intersection m m'
 				let new = M.difference m' m
 				let old = M.difference m m'
-				stoprunning old
+				broadcast STOP old
 				unless paused $
 					startrunning new
 				go h paused (M.union common new)
+			LOSTNET -> do
+				-- force close all cached ssh connections
+				-- (done here so that if there are multiple
+				-- ssh remotes, it's only done once)
+				liftAnnex h forceSshCleanup
+				broadcast LOSTNET m
+				go h True M.empty
 			PAUSE -> do
-				stoprunning m
+				broadcast STOP m
 				go h True M.empty
 			RESUME -> do
 				when paused $
@@ -89,9 +97,9 @@ runController ichan ochan = do
 	startrunning m = forM_ (M.elems m) startrunning'
 	startrunning' (transport, _) = void $ async transport
 	
-	-- Ask the transport nicely to stop.
-	stoprunning m = forM_ (M.elems m) stoprunning'
-	stoprunning' (_, c) = writeChan c STOP
+	broadcast msg m = forM_ (M.elems m) send
+	  where
+		send (_, c) = writeChan c msg
 
 -- Generates a map with a transport for each supported remote in the git repo,
 -- except those that have annex.sync = false
diff --git a/RemoteDaemon/Transport/Ssh.hs b/RemoteDaemon/Transport/Ssh.hs
index d6150bb..ba03a25 100644
--- a/RemoteDaemon/Transport/Ssh.hs
+++ b/RemoteDaemon/Transport/Ssh.hs
@@ -84,6 +84,7 @@ transport' r url transporthandle ichan ochan = do
 		msg <- readChan ichan
 		case msg of
 			STOP -> return Stopping
+			LOSTNET -> return Stopping
 			_ -> handlecontrol
 
 	-- Old versions of git-annex-shell that do not support
diff --git a/RemoteDaemon/Types.hs b/RemoteDaemon/Types.hs
index eef7389..aff9101 100644
--- a/RemoteDaemon/Types.hs
+++ b/RemoteDaemon/Types.hs
@@ -42,6 +42,7 @@ data Emitted
 -- Messages that the deamon consumes.
 data Consumed
 	= PAUSE
+	| LOSTNET
 	| RESUME
 	| CHANGED RefList
 	| RELOAD
@@ -63,6 +64,7 @@ instance Proto.Sendable Emitted where
 
 instance Proto.Sendable Consumed where
 	formatMessage PAUSE = ["PAUSE"]
+	formatMessage LOSTNET = ["LOSTNET"]
 	formatMessage RESUME = ["RESUME"]
 	formatMessage (CHANGED refs) =["CHANGED", Proto.serialize refs]
 	formatMessage RELOAD = ["RELOAD"]
@@ -78,6 +80,7 @@ instance Proto.Receivable Emitted where
 
 instance Proto.Receivable Consumed where
 	parseCommand "PAUSE" = Proto.parse0 PAUSE
+	parseCommand "LOSTNET" = Proto.parse0 LOSTNET
 	parseCommand "RESUME" = Proto.parse0 RESUME
 	parseCommand "CHANGED" = Proto.parse1 CHANGED
 	parseCommand "RELOAD" = Proto.parse0 RELOAD
diff --git a/debian/changelog b/debian/changelog
index 1b5b39d..4c1b20d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -10,6 +10,8 @@ git-annex (5.20140413) UNRELEASED; urgency=medium
     set up.
   * sync, assistant, remotedaemon: Use ssh connection caching for git pushes
     and pulls.
+  * remotedaemon: When network connection is lost, close all cached ssh

(Diff truncated)
poll vote (DCIM directory (photos and videos only))
diff --git a/doc/design/assistant/polls/Android_default_directory.mdwn b/doc/design/assistant/polls/Android_default_directory.mdwn
index 869aedf..6d5a07e 100644
--- a/doc/design/assistant/polls/Android_default_directory.mdwn
+++ b/doc/design/assistant/polls/Android_default_directory.mdwn
@@ -4,4 +4,4 @@ Same as the desktop webapp, users will be able to enter a directory they
 want the first time they run it, but to save typing on android, anything
 that gets enough votes will be included in a list of choices as well.
 
-[[!poll open=yes expandable=yes 66 "/sdcard/annex" 6 "Whole /sdcard" 6 "DCIM directory (photos and videos only)" 1 "Same as for regular git-annex. ~/annex/"]]
+[[!poll open=yes expandable=yes 66 "/sdcard/annex" 6 "Whole /sdcard" 7 "DCIM directory (photos and videos only)" 1 "Same as for regular git-annex. ~/annex/"]]

Add doc/bugs/Drop_--from_always_trusts_local_repository.mdwn
diff --git a/doc/bugs/Drop_--from_always_trusts_local_repository.mdwn b/doc/bugs/Drop_--from_always_trusts_local_repository.mdwn
new file mode 100644
index 0000000..a1b27cf
--- /dev/null
+++ b/doc/bugs/Drop_--from_always_trusts_local_repository.mdwn
@@ -0,0 +1,44 @@
+### Please describe the problem.
+
+The command `git annex drop --from` always trusts the local repository, even if
+it is marked as untrusted.
+
+
+### What steps will reproduce the problem?
+[[!format sh """
+mkdir t u; cd t; git init; git commit --allow-empty -m "Initial commit"; git annex init "Trusted"; date > file; git annex add file; git commit -m "Add file"; cd ../u; git init; git remote add t ../t; git fetch t; git merge t/master; git annex init "Untrusted"; git annex untrust .; git annex get file; cd ../t; git remote add u ../u; git fetch u; cd ..
+"""]]
+
+Create two repositories, *t* (trusted) and *u* (untrusted). A file is in both
+repositories. When performing `git annex drop file` in repository *t*, `git
+annex` will abort because there are not enough copies. But when performing `git
+annex drop --from t file` in *u*, git annex will delete the copy.
+
+
+### What version of git-annex are you using? On what operating system?
+
+Bug was introduced with 6c31e3a8 and still exists in current master (d955cfe7).
+
+
+### Please provide any additional information below.
+
+The following change seems to solve the problem. (First time working with
+Haskell, please excuse the crude code.)
+
+[[!format diff """
+diff --git a/Command/Drop.hs b/Command/Drop.hs
+index 269c4c2..09ea99a 100644
+--- a/Command/Drop.hs
++++ b/Command/Drop.hs
+@@ -82,8 +82,9 @@ performRemote key afile numcopies remote = lockContent key $ do
+        (remotes, trusteduuids) <- Remote.keyPossibilitiesTrusted key
+        present <- inAnnex key
+        u <- getUUID
++       level <- lookupTrust u
+        let have = filter (/= uuid) $
+-               if present then u:trusteduuids else trusteduuids
++               if present && level <= SemiTrusted then u:trusteduuids else trusteduuids
+        untrusteduuids <- trustGet UnTrusted
+        let tocheck = filter (/= remote) $
+                Remote.remotesWithoutUUID remotes (have++untrusteduuids)
+"""]]

removed
diff --git a/doc/encryption/comment_2_f19c9bb519a7017f0731fd0e8780ed74._comment b/doc/encryption/comment_2_f19c9bb519a7017f0731fd0e8780ed74._comment
deleted file mode 100644
index bf43303..0000000
--- a/doc/encryption/comment_2_f19c9bb519a7017f0731fd0e8780ed74._comment
+++ /dev/null
@@ -1,22 +0,0 @@
-[[!comment format=mdwn
- username="https://openid.stackexchange.com/user/e65e6d0e-58ba-41de-84cc-1f2ba54cf574"
- nickname="Mica Semrick"
- subject="Encrypt with pub or sub?"
- date="2014-04-08T03:56:36Z"
- content="""
-Forgive me, I'm a bit new to PGP.
-
-I do: 
-
-    $ gpg --list-keys
-    /home/user/.gnupg/pubring.gpg
-    ------------------------------
-    pub   2048R/41363A6A 2014-04-03
-    uid                  A Guy (git-annex key) <A@guy.com>
-    sub   2048R/77998J8TDY 2014-04-03
-
-and see the pub and the sub key.
-
-When I init a new special remote and want encryption, should I give the init command the pub or the sub key? Or does git annex sort that out itself?
-
-"""]]

devblog
diff --git a/doc/devblog/day_151__birthday_bug.mdwn b/doc/devblog/day_151__birthday_bug.mdwn
new file mode 100644
index 0000000..251bfb9
--- /dev/null
+++ b/doc/devblog/day_151__birthday_bug.mdwn
@@ -0,0 +1,18 @@
+Pushed out a new release today, fixing two important bugs, followed by a
+second release which fixed the bugs harder.
+
+Automatic upgrading was broken on OSX. The webapp will tell you upgrading
+failed, and you'll need to manually download the .dmg and install it.
+
+With help from Maximiliano Curia, finally tracked down a bug I have been
+chasing for a while where the assistant would start using a lot of CPU
+while not seeming to be busy doing anything. Turned out to be triggered by
+a scheduled fsck that was configured to run once a month with no particular
+day specified.
+
+That bug turned out to affect users who first scheduled such a fsck job
+after the 11th day of the month. So I expedited putting a release out to
+avoid anyone else running into it starting tomorrow.
+
+(Oddly, the 11th day of this month also happens to be my birthday. I did not
+expect to have to cut 2 releases today..)

add news item for git-annex 5.20140412
diff --git a/doc/news/version_5.20140306.mdwn b/doc/news/version_5.20140306.mdwn
deleted file mode 100644
index ef30249..0000000
--- a/doc/news/version_5.20140306.mdwn
+++ /dev/null
@@ -1,34 +0,0 @@
-git-annex 5.20140306 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * sync: Fix bug in direct mode that caused a file that was not
-     checked into git to be deleted when there was a conflicting
-     merge with a remote.
-   * webapp: Now supports HTTPS.
-   * webapp: No longer supports a port specified after --listen, since
-     it was buggy, and that use case is better supported by setting up HTTPS.
-   * annex.listen can be configured, instead of using --listen
-   * annex.startupscan can be set to false to disable the assistant's startup
-     scan.
-   * Probe for quvi version at run time.
-   * webapp: Filter out from Switch Repository list any
-     repositories listed in autostart file that don't have a
-     git directory anymore. (Or are bare)
-   * webapp: Refuse to start in a bare git repository.
-   * assistant --autostart: Refuse to start in a bare git repository.
-   * webapp: Don't list the public repository group when editing a
-     git repository; it only makes sense for special remotes.
-   * view, vfilter: Add support for filtering tags and values out of a view,
-     using !tag and field!=value.
-   * vadd: Allow listing multiple desired values for a field.
-   * view: Refuse to enter a view when no branch is currently checked out.
-   * metadata: To only set a field when it's not already got a value, use
-     -s field?=value
-   * Run .git/hooks/pre-commit-annex whenever a commit is made.
-   * sync: Automatically resolve merge conflict between and annexed file
-     and a regular git file.
-   * glacier: Pass --region to glacier checkpresent.
-   * webdav: When built with a new enough haskell DAV (0.6), disable
-     the http response timeout, which was only 5 seconds.
-   * webapp: Include no-pty in ssh authorized\_keys lines.
-   * assistant: Smarter log file rotation, which takes free disk space
-     into account."""]]
\ No newline at end of file
diff --git a/doc/news/version_5.20140412.mdwn b/doc/news/version_5.20140412.mdwn
new file mode 100644
index 0000000..7e9267a
--- /dev/null
+++ b/doc/news/version_5.20140412.mdwn
@@ -0,0 +1,3 @@
+git-annex 5.20140412 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Last release didn't quite fix the high cpu issue in all cases, this should."""]]
\ No newline at end of file

add news item for git-annex 5.20140411
diff --git a/doc/news/version_5.20140227.mdwn b/doc/news/version_5.20140227.mdwn
deleted file mode 100644
index 57f0c9a..0000000
--- a/doc/news/version_5.20140227.mdwn
+++ /dev/null
@@ -1,32 +0,0 @@
-git-annex 5.20140227 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * metadata: Field names limited to alphanumerics and a few whitelisted
-     punctuation characters to avoid issues with views, etc.
-   * metadata: Field names are now case insensative.
-   * When constructing views, metadata is available about the location of the
-     file in the view's reference branch. Allows incorporating parts of the
-     directory hierarchy in a view.
-     For example `git annex view tag=* podcasts/=*` makes a view in the form
-     tag/showname.
-   * --metadata field=value can now use globs to match, and matches
-     case insensatively, the same as git annex view field=value does.
-   * annex.genmetadata can be set to make git-annex automatically set
-     metadata (year and month) when adding files.
-   * Make annex.web-options be used in several places that call curl.
-   * Fix handling of rsync remote urls containing a username,
-     including rsync.net.
-   * Preserve metadata when staging a new version of an annexed file.
-   * metadata: Support --json
-   * webapp: Fix creation of box.com and Amazon S3 and Glacier
-     repositories, broken in 5.20140221.
-   * webdav: When built with DAV 0.6.0, use the new DAV monad to avoid
-     locking files, which is not needed by git-annex's use of webdav, and
-     does not work on Box.com.
-   * webdav: Fix path separator bug when used on Windows.
-   * repair: Optimise unpacking of pack files, and avoid repeated error
-     messages about corrupt pack files.
-   * Add build dep on regex-compat to fix build on mipsel, which lacks
-     regex-tdfa.
-   * Disable test suite on sparc, which is missing optparse-applicative.
-   * Put non-object tmp files in .git/annex/misctmp, leaving .git/annex/tmp
-     for only partially transferred objects."""]]
\ No newline at end of file
diff --git a/doc/news/version_5.20140411.mdwn b/doc/news/version_5.20140411.mdwn
new file mode 100644
index 0000000..8e4bb21
--- /dev/null
+++ b/doc/news/version_5.20140411.mdwn
@@ -0,0 +1,13 @@
+git-annex 5.20140411 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * importfeed: Filename template can now contain an itempubdate variable.
+     Needs feed 0.3.9.2.
+   * Fix rsync progress parsing in locales that use comma in number display.
+     Closes: #[744148](http://bugs.debian.org/744148)
+   * assistant: Fix high CPU usage triggered when a monthly fsck is scheduled,
+     and the last time the job ran was a day of the month &gt; 12. This caused a
+     runaway loop. Thanks to Anarcat for his assistance, and to Maximiliano
+     Curia for identifying the cause of this bug.
+   * Remove wget from OSX dmg, due to issues with cert paths that broke
+     git-annex automatic upgrading. Instead, curl is used, unless the
+     OSX system has wget installed, which will then be used."""]]
\ No newline at end of file

prep release
diff --git a/debian/changelog b/debian/changelog
index 55c1ba3..bd82732 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-git-annex (5.20140406) UNRELEASED; urgency=medium
+git-annex (5.20140411) unstable; urgency=medium
 
   * importfeed: Filename template can now contain an itempubdate variable.
     Needs feed 0.3.9.2.
@@ -12,7 +12,7 @@ git-annex (5.20140406) UNRELEASED; urgency=medium
     runaway loop. Thanks to Anarcat for his assistance, and to Maximiliano
     Curia for identifying the cause of this bug.
 
- -- Joey Hess <joeyh@debian.org>  Mon, 07 Apr 2014 16:22:02 -0400
+ -- Joey Hess <joeyh@debian.org>  Fri, 11 Apr 2014 14:59:49 -0400
 
 git-annex (5.20140405) unstable; urgency=medium
 
diff --git a/doc/assistant/release_notes.mdwn b/doc/assistant/release_notes.mdwn
index 7f13ce9..1ed622b 100644
--- a/doc/assistant/release_notes.mdwn
+++ b/doc/assistant/release_notes.mdwn
@@ -1,4 +1,7 @@
-## version 5.20140406
+## version 5.20140411
+
+This release fixes a bug that could cause the assistant to use a *lot* of
+CPU, when monthly fscking was set up.
 
 Automatic upgrading was broken on OSX for previous versions. This has been
 fixed, but you'll need to manually upgrade to this version to get it going
diff --git a/git-annex.cabal b/git-annex.cabal
index 59b7b3a..ccbd147 100644
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -1,5 +1,5 @@
 Name: git-annex
-Version: 5.20140405
+Version: 5.20140411
 Cabal-Version: >= 1.8
 License: GPL-3
 Maintainer: Joey Hess <joey@kitenet.net>

assistant: Fix high CPU usage triggered when a monthly fsck is scheduled, and the last time the job ran was a day of the month > 12. This caused a runaway loop. Thanks to Anarcat for his assistance, and to Maximiliano Curia for identifying the cause of this bug.
diff --git a/Utility/Scheduled.hs b/Utility/Scheduled.hs
index 11e3b56..e4b03aa 100644
--- a/Utility/Scheduled.hs
+++ b/Utility/Scheduled.hs
@@ -121,7 +121,7 @@ calcNextTime (Schedule recurrance scheduledtime) lasttime currenttime
 					| otherwise -> skip 1
 		Monthly Nothing
 			| afterday -> skip 1
-			| maybe True (\old -> mnum day > mday old && mday day >= (mday old `mod` minmday)) lastday ->
+			| maybe True (\old -> mnum day > mnum old && mday day >= (mday old `mod` minmday)) lastday ->
 				-- Window only covers current month,
 				-- in case there is a Divisible requirement.
 				Just $ window day (endOfMonth day)
diff --git a/debian/changelog b/debian/changelog
index 00ac22c..55c1ba3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,10 @@ git-annex (5.20140406) UNRELEASED; urgency=medium
     OSX system has wget installed, which will then be used.
   * Fix rsync progress parsing in locales that use comma in number display.
     Closes: #744148
+  * assistant: Fix high CPU usage triggered when a monthly fsck is scheduled,
+    and the last time the job ran was a day of the month > 12. This caused a
+    runaway loop. Thanks to Anarcat for his assistance, and to Maximiliano
+    Curia for identifying the cause of this bug.
 
  -- Joey Hess <joeyh@debian.org>  Mon, 07 Apr 2014 16:22:02 -0400
 
diff --git a/doc/bugs/assistant_eats_all_CPU.mdwn b/doc/bugs/assistant_eats_all_CPU.mdwn
index 4939bf4..719fca4 100644
--- a/doc/bugs/assistant_eats_all_CPU.mdwn
+++ b/doc/bugs/assistant_eats_all_CPU.mdwn
@@ -520,3 +520,10 @@ $ ps -O start xf | grep git-annex
 13761 23:56:38 Z ?        00:00:00      \_ [git] <defunct>
  6252 12:56:59 S ?        00:01:09 /usr/bin/emacs23
 """]]
+
+#### This bug is fixed
+
+> [[fixed|done]]. This was a Cronner bug, triggered when you had a
+> scheduled fsck job that runs monthly at any time, and the last time it ran was on a day of a
+> month > 12. Workaround: Disable scheduled fsck jobs, or change them to
+> run on a specific day of the month. Or upgrade. --[[Joey]]

Added a comment
diff --git a/doc/bugs/assistant_eats_all_CPU/comment_23_48a4c8d9dcc6cec243c6072090f26b6d._comment b/doc/bugs/assistant_eats_all_CPU/comment_23_48a4c8d9dcc6cec243c6072090f26b6d._comment
new file mode 100644
index 0000000..b6d2dec
--- /dev/null
+++ b/doc/bugs/assistant_eats_all_CPU/comment_23_48a4c8d9dcc6cec243c6072090f26b6d._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="http://joeyh.name/"
+ ip="209.250.56.191"
+ subject="comment 23"
+ date="2014-04-11T16:32:47Z"
+ content="""
+<maxy> the clock_gettime(0x2 and clock_gettime(0x3 are consistent with getCurrentTime and getTimeZone of nextTime
+
+So, that strongly points to the Cronner thread, and I doubt this is specific to stable at all.
+
+Please run git-annex vicfg, and paste all the \"schedule\" lines, from a repository that has the problem. That should allow me to reproduce and fix this bug.
+"""]]

typo
diff --git a/doc/git-annex-shell.mdwn b/doc/git-annex-shell.mdwn
index eafb164..26ccb9a 100644
--- a/doc/git-annex-shell.mdwn
+++ b/doc/git-annex-shell.mdwn
@@ -67,7 +67,7 @@ first "/~/" or "/~user/" is expanded to the specified home directory.
 
 * notifychanges
 
-  This is used by `git-annex remote-daemon` to be notified when
+  This is used by `git-annex remotedaemon` to be notified when
   refs in the remote repository are changed.
 
 * gcryptsetup gcryptid

note that GIT_ANNEX_SHELL_READONLY does not imply GIT_ANNEX_SHELL_LIMITED
diff --git a/doc/git-annex-shell.mdwn b/doc/git-annex-shell.mdwn
index c6e8c05..eafb164 100644
--- a/doc/git-annex-shell.mdwn
+++ b/doc/git-annex-shell.mdwn
@@ -106,6 +106,9 @@ changed.
 
   If set, disallows any command that could modify the repository.
 
+  Note that this does not prevent passing commands on to git-shell.
+  For that, you also need ...
+
 * GIT_ANNEX_SHELL_LIMITED
 
   If set, disallows running git-shell to handle unknown commands.

update for g3
diff --git a/doc/tips/using_gitolite_with_git-annex.mdwn b/doc/tips/using_gitolite_with_git-annex.mdwn
index fcc3f96..746b6b1 100644
--- a/doc/tips/using_gitolite_with_git-annex.mdwn
+++ b/doc/tips/using_gitolite_with_git-annex.mdwn
@@ -3,8 +3,6 @@ manager. Here's how to add git-annex support to gitolite, so you can
 `git annex copy` files to a gitolite repository, and `git annex get`
 files from it.
 
-Warning : The method described here works with gitolite version g2, avaible in the g2 branch on github. There is an experimental support for g3 in the git-annex branch, if you tested it please add some feedback.
-
 A nice feature of using gitolite with git-annex is that users can be given
 read-only access to a repository, and this allows them to `git annex get`
 file contents, but not change anything.
@@ -12,7 +10,8 @@ file contents, but not change anything.
 First, you need new enough versions:
 
 * gitolite 2.2 is needed -- this version contains a git-annex-shell ADC
-  and supports "ua" ADCs.
+  and supports "ua" ADCs. Alternatively, gitoline g3 also recently added
+  support for git-annex.
 * git-annex 3.20111016 or newer needs to be installed on the gitolite
   server. Don't install an older version, it wouldn't be secure!
 
@@ -39,6 +38,13 @@ cd /usr/local/lib/gitolite/adc/ua/
 cp gitolite/contrib/adc/git-annex-shell .
 </pre>
 
+If using gitolite g3, an additional setup step is needed:
+In the ENABLE list in the rc file, add an entry like this:
+
+<pre>
+	'git-annex-shell ua',
+</pre>
+
 Now all gitolite repositories can be used with git-annex just as any
 ssh remote normally would be used. For example:
 

diff --git a/doc/forum/git_annex_assistant_-_Changing_repository_information.mdwn b/doc/forum/git_annex_assistant_-_Changing_repository_information.mdwn
new file mode 100644
index 0000000..c4ef39a
--- /dev/null
+++ b/doc/forum/git_annex_assistant_-_Changing_repository_information.mdwn
@@ -0,0 +1 @@
+Here's one thing I don't fully understand yet. If I add a remote repository, like an archive repository on Box—or if I want to change a transfer repository to an archive repository—do I need to add it or change it separately on each of my computers? Or just one? 

update
diff --git a/doc/assistant/release_notes.mdwn b/doc/assistant/release_notes.mdwn
index f9de09e..7f13ce9 100644
--- a/doc/assistant/release_notes.mdwn
+++ b/doc/assistant/release_notes.mdwn
@@ -2,7 +2,9 @@
 
 Automatic upgrading was broken on OSX for previous versions. This has been
 fixed, but you'll need to manually upgrade to this version to get it going
-again.
+again. (Note that the fix is currently only available in the daily builds,
+not a released version.) Workaround: Remove the wget bundled inside the
+git-annex dmg.
 
 ## version 5.20140221
 

note automatic upgrade issue
diff --git a/doc/assistant/release_notes.mdwn b/doc/assistant/release_notes.mdwn
index 13b7c62..f9de09e 100644
--- a/doc/assistant/release_notes.mdwn
+++ b/doc/assistant/release_notes.mdwn
@@ -1,3 +1,9 @@
+## version 5.20140406
+
+Automatic upgrading was broken on OSX for previous versions. This has been
+fixed, but you'll need to manually upgrade to this version to get it going
+again.
+
 ## version 5.20140221
 
 The Windows port of the assistant and webapp is now considered to be beta

fix title (#150)
diff --git a/doc/devblog/day_149__signal.mdwn b/doc/devblog/day_149__signal.mdwn
index 6a085b1..7327c67 100644
--- a/doc/devblog/day_149__signal.mdwn
+++ b/doc/devblog/day_149__signal.mdwn
@@ -1,3 +1,5 @@
+[[!meta title="day 150 signal"]]
+
 The git-remote-daemon now robustly handles loss of signal, with
 reconnection backoffs. And it detects if the remote ssh server has a too
 old version of git-annex-shell and the webapp will display a warning

diff --git a/doc/todo/Time_Stamping_of_Events_in_Webapp.mdwn b/doc/todo/Time_Stamping_of_Events_in_Webapp.mdwn
new file mode 100644
index 0000000..a1f3fe6
--- /dev/null
+++ b/doc/todo/Time_Stamping_of_Events_in_Webapp.mdwn
@@ -0,0 +1 @@
+Currently events happening in the webapp (sync upload etc. on the right) has no time stamp thus user has no way to tell when was the last sync happened. Which is problematic when not using XMPP and repos lag behind.

diff --git a/doc/todo/LIst_of_Available_Remotes_in_Webapp.mdwn b/doc/todo/LIst_of_Available_Remotes_in_Webapp.mdwn
new file mode 100644
index 0000000..89274bb
--- /dev/null
+++ b/doc/todo/LIst_of_Available_Remotes_in_Webapp.mdwn
@@ -0,0 +1 @@
+When using git-annex in a distributed fashion (lots of repos everywhere) It is easy to lose track of which remotes has a particular repo and enable it. Currently I have to run `git annex info` and see which remotes are available then add them through the webapp. Would it be possible to make webapp show all repos not just the ones it is syncing give an option to enable it.

Added a comment: I can't add google drive as remote
diff --git a/doc/tips/googledriveannex/comment_2_c98c00e87bc921158c9c3698fd9f89c9._comment b/doc/tips/googledriveannex/comment_2_c98c00e87bc921158c9c3698fd9f89c9._comment
new file mode 100644
index 0000000..e90903b
--- /dev/null
+++ b/doc/tips/googledriveannex/comment_2_c98c00e87bc921158c9c3698fd9f89c9._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawl64jV2rE8GMogJ6XuqESSkz78RVBgVdGw"
+ nickname="Mesut"
+ subject="I can't add google drive as remote"
+ date="2014-04-10T07:55:56Z"
+ content="""
+Hi,
+
+I am new to git-annex and I want to use google drive as remote but I can't.
+
+I create syslink to `googledriveannex` in `/usr/local/bin`.
+
+When I execute below command, command waiting but not make anything:
+
+`$ git annex initremote googledrive type=external externaltype=googledrive encryption=shared folder=gitannex`
+
+`initremote googledrive (encryption setup)` # Waiting but does not do anything.
+
+What I am doing wrong?
+
+Thanks for helps
+
+"""]]

Added a comment
diff --git a/doc/bugs/git-annex_fails_to_initialize_under_Windows/comment_2_b9a3a0104bc56f9110fc58c9df140f12._comment b/doc/bugs/git-annex_fails_to_initialize_under_Windows/comment_2_b9a3a0104bc56f9110fc58c9df140f12._comment
new file mode 100644
index 0000000..1fcfc5a
--- /dev/null
+++ b/doc/bugs/git-annex_fails_to_initialize_under_Windows/comment_2_b9a3a0104bc56f9110fc58c9df140f12._comment
@@ -0,0 +1,34 @@
+[[!comment format=mdwn
+ username="ayutheos"
+ ip="49.124.177.13"
+ subject="comment 2"
+ date="2014-04-10T07:52:36Z"
+ content="""
+I'm getting this error too. 
+
+    user@NOTEBOOK /d/pictures
+    $ git annex init \"photos\"
+    init photos
+      Detected a filesystem without fifo support.
+
+      Disabling ssh connection caching.
+
+      Detected a crippled filesystem.
+
+      Enabling direct mode.
+    fatal: index file open failed: Invalid argument
+    git-annex: git [Param \"checkout\",Param \"-q\",Param \"-B\",Param \"annex/direct/master\"] failed
+
+git-annex version:
+
+    user@NOTEBOOK /d/pictures
+    $ git annex version
+    git-annex version: 5.20140403-gdfa17fc
+    build flags: Assistant Webapp Webapp-secure Pairing Testsuite S3 WebDAV DNS Feeds Quvi TDFA CryptoHash
+    key/value backends: SHA256E SHA1E SHA512E SHA224E SHA384E SKEIN256E SKEIN512E SHA256 SHA1 SHA512 SHA224 SHA384 SKEIN256 SKEIN512 WORM URL
+    remote types: git gcrypt S3 bup directory rsync web webdav tahoe glacier hook external
+    local repository version: 5
+    supported repository version: 5
+    upgrade supported from repository versions: 2 3 4
+
+"""]]

removed
diff --git a/doc/tips/googledriveannex/comment_2_6d6cc9cb7d03f6779d4bdc52ddcfab86._comment b/doc/tips/googledriveannex/comment_2_6d6cc9cb7d03f6779d4bdc52ddcfab86._comment
deleted file mode 100644
index 0574d37..0000000
--- a/doc/tips/googledriveannex/comment_2_6d6cc9cb7d03f6779d4bdc52ddcfab86._comment
+++ /dev/null
@@ -1,23 +0,0 @@
-[[!comment format=mdwn
- username="https://www.google.com/accounts/o8/id?id=AItOawl64jV2rE8GMogJ6XuqESSkz78RVBgVdGw"
- nickname="Mesut"
- subject="I can't add special remotes"
- date="2014-04-10T07:50:39Z"
- content="""
-Hi,
-
-I am new to git-annex and I want to use google drive as remote but I can't.
-
-I create syslink to `googledriveannex` in `/usr/local/bin`.
-
-When I execute below command, command waiting but not make anything:
-
-`````
-$ git annex initremote googledrive type=external externaltype=googledrive encryption=shared folder=gitannex
-initremote googledrive (encryption setup) # Waiting but does not do anything.
-`````
-
-What I am doing wrong?
-
-Thanks for helps
-"""]]

Added a comment: I can't add special remotes
diff --git a/doc/tips/googledriveannex/comment_2_6d6cc9cb7d03f6779d4bdc52ddcfab86._comment b/doc/tips/googledriveannex/comment_2_6d6cc9cb7d03f6779d4bdc52ddcfab86._comment
new file mode 100644
index 0000000..0574d37
--- /dev/null
+++ b/doc/tips/googledriveannex/comment_2_6d6cc9cb7d03f6779d4bdc52ddcfab86._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawl64jV2rE8GMogJ6XuqESSkz78RVBgVdGw"
+ nickname="Mesut"
+ subject="I can't add special remotes"
+ date="2014-04-10T07:50:39Z"
+ content="""
+Hi,
+
+I am new to git-annex and I want to use google drive as remote but I can't.
+
+I create syslink to `googledriveannex` in `/usr/local/bin`.
+
+When I execute below command, command waiting but not make anything:
+
+`````
+$ git annex initremote googledrive type=external externaltype=googledrive encryption=shared folder=gitannex
+initremote googledrive (encryption setup) # Waiting but does not do anything.
+`````
+
+What I am doing wrong?
+
+Thanks for helps
+"""]]

update
diff --git a/doc/design/roadmap.mdwn b/doc/design/roadmap.mdwn
index 3fa261e..b7c4883 100644
--- a/doc/design/roadmap.mdwn
+++ b/doc/design/roadmap.mdwn
@@ -11,7 +11,7 @@ Now in the
 * Month 5 user-driven features and polishing
 * Month 6 get Windows out of beta, [[!traillink design/metadata text="metadata and views"]]
 * Month 7 user-driven features and polishing
-* **Month 8 [[!traillink assistant/telehash]]**
+* **Month 8 [[!traillink git-remote-daemon]] [[!traillink assistant/telehash]]**
 * Month 9 [[!traillink assistant/gpgkeys]] [[!traillink assistant/sshpassword]]
 * Month 10 get [[assistant/Android]] out of beta
 * Month 11 [[!traillink assistant/chunks]] [[!traillink assistant/deltas]]

devblog
diff --git a/doc/assistant/connection.png b/doc/assistant/connection.png
new file mode 100644
index 0000000..3cd6bef
Binary files /dev/null and b/doc/assistant/connection.png differ
diff --git a/doc/devblog/day_149__signal.mdwn b/doc/devblog/day_149__signal.mdwn
new file mode 100644
index 0000000..6a085b1
--- /dev/null
+++ b/doc/devblog/day_149__signal.mdwn
@@ -0,0 +1,14 @@
+The git-remote-daemon now robustly handles loss of signal, with
+reconnection backoffs. And it detects if the remote ssh server has a too
+old version of git-annex-shell and the webapp will display a warning
+message.
+
+[[!img /assistant/connection.png]]
+
+Also, made the webapp show a network signal bars icon next to both
+ssh and xmpp remotes that it's currently connected with. And, updated the
+webapp's nudging to set up XMPP to now suggest either an XMPP or a ssh remote.
+
+I think that the `remotecontrol` branch is nearly ready for merging!
+
+Today's work was sponsored by Paul Tagliamonte.

webapp: Show a network signal icon next to ssh remotes that it's currently connected with.
diff --git a/Assistant/DaemonStatus.hs b/Assistant/DaemonStatus.hs
index eb842b7..35f8fc8 100644
--- a/Assistant/DaemonStatus.hs
+++ b/Assistant/DaemonStatus.hs
@@ -26,6 +26,7 @@ import Data.Time.Clock.POSIX
 import Data.Time
 import System.Locale
 import qualified Data.Map as M
+import qualified Data.Set as S
 import qualified Data.Text as T
 
 getDaemonStatus :: Assistant DaemonStatus
@@ -78,6 +79,15 @@ updateSyncRemotes = do
 			M.filter $ \alert ->
 				alertName alert /= Just CloudRepoNeededAlert
 
+changeCurrentlyConnected :: (S.Set UUID -> S.Set UUID) -> Assistant ()
+changeCurrentlyConnected sm = do
+	modifyDaemonStatus_ $ \ds -> ds
+		{ currentlyConnectedRemotes = sm (currentlyConnectedRemotes ds)
+		}
+	v <- currentlyConnectedRemotes <$> getDaemonStatus
+	debug [show v]
+	liftIO . sendNotification =<< syncRemotesNotifier <$> getDaemonStatus
+
 updateScheduleLog :: Assistant ()
 updateScheduleLog =
 	liftIO . sendNotification =<< scheduleLogNotifier <$> getDaemonStatus
diff --git a/Assistant/Threads/RemoteControl.hs b/Assistant/Threads/RemoteControl.hs
index d33a485..a886cae 100644
--- a/Assistant/Threads/RemoteControl.hs
+++ b/Assistant/Threads/RemoteControl.hs
@@ -23,8 +23,9 @@ import qualified Types.Remote as Remote
 import Control.Concurrent
 import Control.Concurrent.Async
 import System.Process (std_in, std_out)
-import qualified Data.Map as M
 import Network.URI
+import qualified Data.Map as M
+import qualified Data.Set as S
 
 remoteControlThread :: NamedThread
 remoteControlThread = namedThread "RemoteControl" $ do
@@ -43,9 +44,9 @@ remoteControlThread = namedThread "RemoteControl" $ do
 	responder <- asIO $ remoteResponderThread fromh urimap
 
 	-- run controller and responder until the remotedaemon dies
-	liftIO $ do
-		void $ controller `concurrently` responder
-		forceSuccessProcess p pid
+	liftIO $ void $ tryNonAsync $ controller `concurrently` responder
+	debug ["remotedaemon exited"]
+	liftIO $ forceSuccessProcess p pid
 
 -- feed from the remoteControl channel into the remotedaemon
 remoteControllerThread :: Handle -> Assistant ()
@@ -61,14 +62,10 @@ remoteResponderThread :: Handle -> MVar (M.Map URI Remote) -> Assistant ()
 remoteResponderThread fromh urimap = go M.empty
   where
 	go syncalerts = do
-		let cont = go syncalerts
-		let withr uri = withRemote uri urimap cont
 		l <- liftIO $ hGetLine fromh
 		case parseMessage l of
-			Just (CONNECTED _uri) -> do
-				cont
-			Just (DISCONNECTED _uri) -> do
-				cont
+			Just (CONNECTED uri) -> changeconnected S.insert uri
+			Just (DISCONNECTED uri) -> changeconnected S.delete uri
 			Just (SYNCING uri) -> withr uri $ \r ->
 				if M.member (Remote.uuid r) syncalerts
 					then go syncalerts
@@ -92,6 +89,12 @@ remoteResponderThread fromh urimap = go M.empty
 			Nothing -> do
 				debug ["protocol error from remotedaemon: ", l]
 				cont
+	  where
+		cont = go syncalerts
+		withr uri = withRemote uri urimap cont
+		changeconnected sm uri = withr uri $ \r -> do
+			changeCurrentlyConnected $ sm $ Remote.uuid r
+			cont
 
 getURIMap :: Annex (M.Map URI Remote)
 getURIMap = Remote.remoteMap' id (mkk . Git.location . Remote.repo)
diff --git a/Assistant/Threads/XMPPClient.hs b/Assistant/Threads/XMPPClient.hs
index ab4de92..d23f695 100644
--- a/Assistant/Threads/XMPPClient.hs
+++ b/Assistant/Threads/XMPPClient.hs
@@ -67,6 +67,7 @@ xmppClient urlrenderer d creds =
 		 - is not retained. -}
 		liftAssistant $
 			updateBuddyList (const noBuddies) <<~ buddyList
+		liftAssistant $ 
 		void client
 		liftAssistant $ modifyDaemonStatus_ $ \s -> s
 			{ xmppClientID = Nothing }
diff --git a/Assistant/Types/DaemonStatus.hs b/Assistant/Types/DaemonStatus.hs
index a618c70..2adad28 100644
--- a/Assistant/Types/DaemonStatus.hs
+++ b/Assistant/Types/DaemonStatus.hs
@@ -52,6 +52,8 @@ data DaemonStatus = DaemonStatus
 	, syncDataRemotes :: [Remote]
 	-- Are we syncing to any cloud remotes?
 	, syncingToCloudRemote :: Bool
+	-- Set of uuids of remotes that are currently connected.
+	, currentlyConnectedRemotes :: S.Set UUID
 	-- List of uuids of remotes that we may have gotten out of sync with.
 	, desynced :: S.Set UUID
 	-- Pairing request that is in progress.
@@ -104,6 +106,7 @@ newDaemonStatus = DaemonStatus
 	<*> pure []
 	<*> pure False
 	<*> pure S.empty
+	<*> pure S.empty
 	<*> pure Nothing
 	<*> newNotificationBroadcaster
 	<*> newNotificationBroadcaster
diff --git a/Assistant/WebApp/RepoList.hs b/Assistant/WebApp/RepoList.hs
index 6a93cb4..1d91659 100644
--- a/Assistant/WebApp/RepoList.hs
+++ b/Assistant/WebApp/RepoList.hs
@@ -33,9 +33,10 @@ import qualified Data.Text as T
 import Data.Function
 import Control.Concurrent
 
-type RepoList = [(RepoDesc, RepoId, Actions)]
+type RepoList = [(RepoDesc, RepoId, CurrentlyConnected, Actions)]
 
 type RepoDesc = String
+type CurrentlyConnected = Bool
 
 {- Actions that can be performed on a repo in the list. -}
 data Actions
@@ -192,13 +193,19 @@ repoList reposelector
 	  where
 	  	getconfig k = M.lookup k =<< M.lookup u m
 		val iscloud r = Just (iscloud, (RepoUUID u, DisabledRepoActions $ r u))
-	list l = liftAnnex $
+	list l = do
+		cc <- currentlyConnectedRemotes <$> liftAssistant getDaemonStatus
 		forM (nubBy ((==) `on` fst) l) $ \(repoid, actions) ->
-			(,,)
-				<$> describeRepoId repoid
+			(,,,)
+				<$> liftAnnex (describeRepoId repoid)
 				<*> pure repoid
+				<*> pure (getCurrentlyConnected repoid cc)
 				<*> pure actions
 
+getCurrentlyConnected :: RepoId -> S.Set UUID -> CurrentlyConnected
+getCurrentlyConnected (RepoUUID u) cc = S.member u cc
+getCurrentlyConnected _ _ = False
+
 getEnableSyncR :: RepoId -> Handler ()
 getEnableSyncR = flipSync True
 
diff --git a/debian/changelog b/debian/changelog
index fcbef3f..bd908fa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,6 +6,8 @@ git-annex (5.20140406) UNRELEASED; urgency=medium
     changes to a ssh remote, and pulls.
     XMPP is no longer needed in this configuration!
     Requires the remote server have git-annex-shell with notifychanges support.
+  * webapp: Show a network signal icon next to ssh remotes that
+    it's currently connected with.
 
  -- Joey Hess <joeyh@debian.org>  Mon, 07 Apr 2014 16:22:02 -0400
 
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index b81a5f3..ca3a59f 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -170,8 +170,6 @@ TODO:
 * Remote system might not be available. Find a smart way to detect it,
   ideally w/o generating network traffic. One way might be to check
   if the ssh connection caching control socket exists, for example.
-* CONNECTED and DISCONNECTED are not wired into any webapp UI; could be
-  used to show an icon when a ssh remote is available
 
 ## telehash 
 
diff --git a/templates/repolist.hamlet b/templates/repolist.hamlet
index 0dc92ed..afc71cd 100644
--- a/templates/repolist.hamlet
+++ b/templates/repolist.hamlet
@@ -11,7 +11,7 @@
         Repositories
   <table .table .table-condensed>
     <tbody #costsortable>
-      $forall (name, repoid, actions) <- repolist
+      $forall (name, repoid, currentlyconnected, actions) <- repolist
         <tr .repoline ##{show repoid}>
           <td .handle>
             <a .btn .btn-mini .disabled>
@@ -26,10 +26,17 @@
                 <i .icon-trash></i> cleaning out..
               $else

(Diff truncated)
typo
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index 8c74433..b81a5f3 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -87,7 +87,7 @@ the webapp.
   Indicates that syncing with a remote is done, and either succeeded
   (1) or failed (0).
 
-* `WARNING`uri string`
+* `WARNING uri string`
 
   A message to display to the user about a remote.
 

make git-remote-daemon ssh transport robust
* Remote system might be available, and connection get lost. Should
reconnect, but needs to avoid bad behavior (ie, constant reconnect
attempts.) Use exponential backoff.
* Detect if old system had a too old git-annex-shell, and show the user
a nice message in the webapp. Required parsing error messages, so perhaps
this code shoudl be removed once enough time has passed..
* Switch the protocol to using remote URI's, rather than remote names.
Names change. Also avoids issues with serialization of names containing
whitespace.
This is nearly ready for merge into master now. I'd still like to make the ssh
transport smarter about reusing ssh connection caching during git pull.
This commit was sponsored by Jim Paris.
diff --git a/Assistant/Threads/RemoteControl.hs b/Assistant/Threads/RemoteControl.hs
index b67b0e0..d33a485 100644
--- a/Assistant/Threads/RemoteControl.hs
+++ b/Assistant/Threads/RemoteControl.hs
@@ -15,11 +15,16 @@ import Utility.SimpleProtocol
 import Assistant.Alert
 import Assistant.Alert.Utility
 import Assistant.DaemonStatus
+import qualified Git
+import qualified Git.Types as Git
+import qualified Remote
+import qualified Types.Remote as Remote
 
 import Control.Concurrent
 import Control.Concurrent.Async
 import System.Process (std_in, std_out)
 import qualified Data.Map as M
+import Network.URI
 
 remoteControlThread :: NamedThread
 remoteControlThread = namedThread "RemoteControl" $ do
@@ -32,8 +37,10 @@ remoteControlThread = namedThread "RemoteControl" $ do
 		, std_out = CreatePipe
 		}
 	
+	urimap <- liftIO . newMVar =<< liftAnnex getURIMap
+
 	controller <- asIO $ remoteControllerThread toh
-	responder <- asIO $ remoteResponderThread fromh
+	responder <- asIO $ remoteResponderThread fromh urimap
 
 	-- run controller and responder until the remotedaemon dies
 	liftIO $ do
@@ -50,31 +57,60 @@ remoteControllerThread toh = do
 		hFlush toh
 
 -- read status messages emitted by the remotedaemon and handle them
-remoteResponderThread :: Handle -> Assistant ()
-remoteResponderThread fromh = go M.empty
+remoteResponderThread :: Handle -> MVar (M.Map URI Remote) -> Assistant ()
+remoteResponderThread fromh urimap = go M.empty
   where
 	go syncalerts = do
+		let cont = go syncalerts
+		let withr uri = withRemote uri urimap cont
 		l <- liftIO $ hGetLine fromh
 		case parseMessage l of
-			Just (CONNECTED _rn) -> do
-				go syncalerts
-			Just (DISCONNECTED _rn) -> do
-				go syncalerts
-			Just (SYNCING rn)
-				| M.member rn syncalerts -> go syncalerts
-				| otherwise -> do
-					i <- addAlert $ syncAlert' [rn]
-					go (M.insert rn i syncalerts)
-			Just (DONESYNCING status rn) ->
-				case M.lookup rn syncalerts of
-					Nothing -> go syncalerts
+			Just (CONNECTED _uri) -> do
+				cont
+			Just (DISCONNECTED _uri) -> do
+				cont
+			Just (SYNCING uri) -> withr uri $ \r ->
+				if M.member (Remote.uuid r) syncalerts
+					then go syncalerts
+					else do
+						i <- addAlert $ syncAlert [r]
+						go (M.insert (Remote.uuid r) i syncalerts)
+			Just (DONESYNCING uri status) -> withr uri $ \r ->
+				case M.lookup (Remote.uuid r) syncalerts of
+					Nothing -> cont
 					Just i -> do
 						let (succeeded, failed) = if status
-							then ([rn], [])
-							else ([], [rn])
+							then ([r], [])
+							else ([], [r])
 						updateAlertMap $ mergeAlert i $
-							syncResultAlert' succeeded failed
-						go (M.delete rn syncalerts)
+							syncResultAlert succeeded failed
+						go (M.delete (Remote.uuid r) syncalerts)
+			Just (WARNING (RemoteURI uri) msg) -> do
+				void $ addAlert $
+					warningAlert ("RemoteControl "++ show uri) msg
+				cont
 			Nothing -> do
 				debug ["protocol error from remotedaemon: ", l]
-				go syncalerts
+				cont
+
+getURIMap :: Annex (M.Map URI Remote)
+getURIMap = Remote.remoteMap' id (mkk . Git.location . Remote.repo)
+  where
+	mkk (Git.Url u) = Just u
+	mkk _ = Nothing
+
+withRemote
+	:: RemoteURI
+	-> MVar (M.Map URI Remote)
+	-> Assistant a
+	-> (Remote -> Assistant a)
+	-> Assistant a
+withRemote (RemoteURI uri) remotemap noremote a = do
+	m <- liftIO $ readMVar remotemap
+	case M.lookup uri m of
+		Just r -> a r
+		Nothing -> do
+			{- Reload map, in case a new remote has been added. -}
+			m' <- liftAnnex getURIMap
+			void $ liftIO $ swapMVar remotemap $ m'
+			maybe noremote a (M.lookup uri m')
diff --git a/Remote.hs b/Remote.hs
index 0f31b99..da33e19 100644
--- a/Remote.hs
+++ b/Remote.hs
@@ -22,6 +22,7 @@ module Remote (
 	remoteList,
 	gitSyncableRemote,
 	remoteMap,
+	remoteMap',
 	uuidDescriptions,
 	byName,
 	byNameOnly,
@@ -64,9 +65,19 @@ import Git.Types (RemoteName)
 import qualified Git
 
 {- Map from UUIDs of Remotes to a calculated value. -}
-remoteMap :: (Remote -> a) -> Annex (M.Map UUID a)
-remoteMap c = M.fromList . map (\r -> (uuid r, c r)) .
-	filter (\r -> uuid r /= NoUUID) <$> remoteList
+remoteMap :: (Remote -> v) -> Annex (M.Map UUID v)
+remoteMap mkv = remoteMap' mkv mkk
+  where
+	mkk r = case uuid r of
+		NoUUID -> Nothing
+		u -> Just u
+
+remoteMap' :: Ord k => (Remote -> v) -> (Remote -> Maybe k) -> Annex (M.Map k v)
+remoteMap' mkv mkk = M.fromList . mapMaybe mk <$> remoteList
+  where
+	mk r = case mkk r of
+		Nothing -> Nothing
+		Just k -> Just (k, mkv r)
 
 {- Map of UUIDs of remotes and their descriptions.
  - The names of Remotes are added to suppliment any description that has
diff --git a/RemoteDaemon/Core.hs b/RemoteDaemon/Core.hs
index 7d07c35..0c29371 100644
--- a/RemoteDaemon/Core.hs
+++ b/RemoteDaemon/Core.hs
@@ -106,7 +106,7 @@ genRemoteMap h@(TransportHandle g _) ochan =
 					ichan <- newChan :: IO (Chan Consumed)
 					return $ Just
 						( r
-						, (transport r (Git.repoDescribe r) h ichan ochan, ichan)
+						, (transport r (RemoteURI u) h ichan ochan, ichan)
 						)
 			_ -> return Nothing
 		_ -> return Nothing
diff --git a/RemoteDaemon/Transport/Ssh.hs b/RemoteDaemon/Transport/Ssh.hs
index 557a3dc..87fcf6f 100644
--- a/RemoteDaemon/Transport/Ssh.hs
+++ b/RemoteDaemon/Transport/Ssh.hs
@@ -13,60 +13,103 @@ import RemoteDaemon.Common
 import Remote.Helper.Ssh
 import qualified RemoteDaemon.Transport.Ssh.Types as SshRemote
 import Utility.SimpleProtocol
+import qualified Git
 import Git.Command
+import Utility.ThreadScheduler
 
 import Control.Concurrent.Chan
 import Control.Concurrent.Async
-import System.Process (std_in, std_out)
+import System.Process (std_in, std_out, std_err)
 
 transport :: Transport
-transport r remotename transporthandle ichan ochan = do
+transport r url transporthandle ichan ochan = do
 	v <- liftAnnex transporthandle $ git_annex_shell r "notifychanges" [] []
 	case v of
 		Nothing -> noop
-		Just (cmd, params) -> go cmd (toCommand params)
+		Just (cmd, params) -> robustly 1 $
+			connect cmd (toCommand params)
   where
-	go cmd params = do
-		(Just toh, Just fromh, _, pid) <- createProcess (proc cmd params)
+	connect cmd params = do
+		(Just toh, Just fromh, Just errh, pid) <-
+			createProcess (proc cmd params)
 			{ std_in = CreatePipe
 			, std_out = CreatePipe
+			, std_err = CreatePipe
 			}
 		
-		let shutdown = do
-			hClose toh

(Diff truncated)
Added a comment
diff --git a/doc/bugs/git_annex_sync_in_direct_mode_does_not_honor_skip-worktree/comment_5_cb98789c50c58f01055183dbaf7b4eba._comment b/doc/bugs/git_annex_sync_in_direct_mode_does_not_honor_skip-worktree/comment_5_cb98789c50c58f01055183dbaf7b4eba._comment
new file mode 100644
index 0000000..d40d2d7
--- /dev/null
+++ b/doc/bugs/git_annex_sync_in_direct_mode_does_not_honor_skip-worktree/comment_5_cb98789c50c58f01055183dbaf7b4eba._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="EvanDeaubl"
+ ip="24.251.129.149"
+ subject="comment 5"
+ date="2014-04-09T03:28:24Z"
+ content="""
+I'm afraid I abandoned this patch. It worked, but was still fidgety for being able to ignore parts of the tree. I found another way to do what I wanted by loading an indirect repo into /data and taking advantage of a surprise side effect in how the /sdcard filesystem translated the symlinks from the ext4 filesystem.
+
+I can probably scare it up from my archives, but it hasn't been kept up to date. The good news is (as I recall) the patch was pretty small.
+
+"""]]

add day's sponsor
diff --git a/doc/devblog/day_149__remote_control_working.mdwn b/doc/devblog/day_149__remote_control_working.mdwn
index 9f92d96..56c108b 100644
--- a/doc/devblog/day_149__remote_control_working.mdwn
+++ b/doc/devblog/day_149__remote_control_working.mdwn
@@ -11,3 +11,5 @@ This is gonna be *awesome*. Much less need for XMPP. Windows will be fully
 usable even without XMPP. Also, most of the work I did today will be fully
 reused when the telehash backend gets built. The telehash-c developer is
 making noises about it being almost ready for use, too!
+
+Today's work was sponsored by Frédéric Schütz.

how to send patches
diff --git a/doc/contribute.mdwn b/doc/contribute.mdwn
index 5dc3eb5..540c1c4 100644
--- a/doc/contribute.mdwn
+++ b/doc/contribute.mdwn
@@ -10,3 +10,6 @@ Help make git-annex better!
   You could work to improve the Android port (Java etc) or improve the
   Javascript and CSS of the git-annex webapp, or work on porting libraries
   needed by the Windows port.
+
+To send patches, either include the patch in a bug report (small patch)
+or put up a branch in a git repository containing your changes.

Added a comment
diff --git a/doc/forum/A_tiny_filesystem__63__/comment_3_3869c0472b50d7cf5e29ac0720f4f20f._comment b/doc/forum/A_tiny_filesystem__63__/comment_3_3869c0472b50d7cf5e29ac0720f4f20f._comment
new file mode 100644
index 0000000..9c1613c
--- /dev/null
+++ b/doc/forum/A_tiny_filesystem__63__/comment_3_3869c0472b50d7cf5e29ac0720f4f20f._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="augusto"
+ ip="177.98.104.136"
+ subject="comment 3"
+ date="2014-04-08T22:46:18Z"
+ content="""
+When I saw Sharebox's page on Github I had the impression it was vaporware. It has a section named \"Planned Interface\" and there are no updates for quite a while.
+
+Is it working? How to install/use it?
+"""]]

diff --git a/doc/forum/Walkthrough_for_direct_mode__63__.mdwn b/doc/forum/Walkthrough_for_direct_mode__63__.mdwn
new file mode 100644
index 0000000..b3fae29
--- /dev/null
+++ b/doc/forum/Walkthrough_for_direct_mode__63__.mdwn
@@ -0,0 +1 @@
+Hello Joey, I would be very much interested in a walkthrough for direct mode, as detailed as the one currently published. I see the comments in the current walkthrough on some differences to direct mode, but to me it is not obvious what best practices for git-annex use would be in direct mode, with and without the assistant. For a mix of Linux, OS X and Windows installations in the homes, it may also be interesting to see how to best set up the individual machines. Many thanks - 

link to the haskell page, which has many teaching resources about it
diff --git a/doc/index.mdwn b/doc/index.mdwn
index 9536ee1..fd16621 100644
--- a/doc/index.mdwn
+++ b/doc/index.mdwn
@@ -39,7 +39,7 @@ files with git.
 
 ----
 
-git-annex is [[Free Software|license]], written in Haskell.
+git-annex is [[Free Software|license]], written in [Haskell](http://www.haskell.org/).
 You can [[contribute]]!
 
 git-annex's wiki is powered by [Ikiwiki](http://ikiwiki.info/) and

devblog
diff --git a/doc/devblog/day_149__remote_control_working.mdwn b/doc/devblog/day_149__remote_control_working.mdwn
new file mode 100644
index 0000000..9f92d96
--- /dev/null
+++ b/doc/devblog/day_149__remote_control_working.mdwn
@@ -0,0 +1,13 @@
+[[design/git-remote-daemon]] is tied into the assistant, and working!
+Since it's not really ready yet, this is in the `remotecontrol` branch.
+
+My test case for this is two client repositories, both running
+the assistant. Both have a bare git repository, accessed over ssh,
+set up as their only remote, and no other way to keep in touch with
+one-another. When I change a file in one repository,
+the other one instantly notices the change and syncs.
+
+This is gonna be *awesome*. Much less need for XMPP. Windows will be fully
+usable even without XMPP. Also, most of the work I did today will be fully
+reused when the telehash backend gets built. The telehash-c developer is
+making noises about it being almost ready for use, too!

add contribute page, mention haskell on front page
diff --git a/doc/contribute.mdwn b/doc/contribute.mdwn
new file mode 100644
index 0000000..5dc3eb5
--- /dev/null
+++ b/doc/contribute.mdwn
@@ -0,0 +1,12 @@
+Help make git-annex better!
+
+* This website is a wiki, so you can edit and improve any page.
+* Write a [[new_tip|tips]] explaining how to accomplish something with
+  git-annex.
+* [[download]] the source code and send patches!
+* If you know Haskell, git-annex has lots of Haskell code that
+  could be improved. See the [[coding_style]] and have at it.
+* If you don't know Haskell, git-annex has many other coding opportunities.
+  You could work to improve the Android port (Java etc) or improve the
+  Javascript and CSS of the git-annex webapp, or work on porting libraries
+  needed by the Windows port.
diff --git a/doc/index.mdwn b/doc/index.mdwn
index 57bfe24..9536ee1 100644
--- a/doc/index.mdwn
+++ b/doc/index.mdwn
@@ -39,7 +39,8 @@ files with git.
 
 ----
 
-git-annex is [[Free Software|license]]
+git-annex is [[Free Software|license]], written in Haskell.
+You can [[contribute]]!
 
 git-annex's wiki is powered by [Ikiwiki](http://ikiwiki.info/) and
 hosted by [Branchable](http://branchable.com/).

update
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index 169ca32..f7de3a2 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -160,13 +160,17 @@ No pushing is done for CHANGED, since git handles ssh natively.
 
 TODO:
 
+* The NetWatcher does not detect network loss, only network gain,
+  so PAUSE is only sent when a new network is detected, followed
+  immediately by RESUME.
 * Remote system might not be available. Find a smart way to detect it,
   ideally w/o generating network traffic. One way might be to check
   if the ssh connection caching control socket exists, for example.
 * Remote system might be available, and connection get lost. Should
   reconnect, but needs to avoid bad behavior (ie, constant reconnect
   attempts.)
-* Detect if old system had a too old git-annex-shell and avoid bad behavior
+* Detect if old system had a too old git-annex-shell and avoid bad
+  behavior.
 * CONNECTED and DISCONNECTED are not wired into any webapp UI; could be
   used to show an icon when a ssh remote is available
 

assistant: Now detects immediately when other repositories push changes to
a ssh remote, and pulls.
XMPP is no longer needed in this configuration!
Requires the remote server have git-annex-shell with notifychanges support.
(untested)
This commit was sponsored by Geog Wechslberger.
diff --git a/Assistant.hs b/Assistant.hs
index 67398f2..b5cacea 100644
--- a/Assistant.hs
+++ b/Assistant.hs
@@ -21,6 +21,7 @@ import Assistant.Threads.Pusher
 import Assistant.Threads.Merger
 import Assistant.Threads.TransferWatcher
 import Assistant.Threads.Transferrer
+import Assistant.Threads.RemoteControl
 import Assistant.Threads.SanityChecker
 import Assistant.Threads.Cronner
 import Assistant.Threads.ProblemFixer
@@ -147,6 +148,7 @@ startDaemon assistant foreground startdelay cannotrun listenhost startbrowser =
 				, assist $ transferWatcherThread
 				, assist $ transferPollerThread
 				, assist $ transfererThread
+				, assist $ remoteControlThread
 				, assist $ daemonStatusThread
 				, assist $ sanityCheckerDailyThread urlrenderer
 				, assist $ sanityCheckerHourlyThread
diff --git a/Assistant/Alert.hs b/Assistant/Alert.hs
index 192952f..018fbf5 100644
--- a/Assistant/Alert.hs
+++ b/Assistant/Alert.hs
@@ -16,6 +16,7 @@ import qualified Remote
 import Utility.Tense
 import Logs.Transfer
 import Types.Distribution
+import Git.Types (RemoteName)
 
 import Data.String
 import qualified Data.Text as T
@@ -117,11 +118,14 @@ commitAlert :: Alert
 commitAlert = activityAlert Nothing
 	[Tensed "Committing" "Committed", "changes to git"]
 
-showRemotes :: [Remote] -> TenseChunk
-showRemotes = UnTensed . T.intercalate ", " . map (T.pack . Remote.name)
+showRemotes :: [RemoteName] -> TenseChunk
+showRemotes = UnTensed . T.intercalate ", " . map T.pack
 
 syncAlert :: [Remote] -> Alert
-syncAlert rs = baseActivityAlert
+syncAlert = syncAlert' . map Remote.name
+
+syncAlert' :: [RemoteName] -> Alert
+syncAlert' rs = baseActivityAlert
 	{ alertName = Just SyncAlert
 	, alertHeader = Just $ tenseWords
 		[Tensed "Syncing" "Synced", "with", showRemotes rs]
@@ -130,7 +134,12 @@ syncAlert rs = baseActivityAlert
 	}
 
 syncResultAlert :: [Remote] -> [Remote] -> Alert
-syncResultAlert succeeded failed = makeAlertFiller (not $ null succeeded) $
+syncResultAlert succeeded failed = syncResultAlert'
+	(map Remote.name succeeded)
+	(map Remote.name failed)
+
+syncResultAlert' :: [RemoteName] -> [RemoteName] -> Alert
+syncResultAlert' succeeded failed = makeAlertFiller (not $ null succeeded) $
 	baseActivityAlert
 		{ alertName = Just SyncAlert
 		, alertHeader = Just $ tenseWords msg
diff --git a/Assistant/Monad.hs b/Assistant/Monad.hs
index 7c28c7f..350e3d3 100644
--- a/Assistant/Monad.hs
+++ b/Assistant/Monad.hs
@@ -43,6 +43,7 @@ import Assistant.Types.RepoProblem
 import Assistant.Types.Buddies
 import Assistant.Types.NetMessager
 import Assistant.Types.ThreadName
+import Assistant.Types.RemoteControl
 
 newtype Assistant a = Assistant { mkAssistant :: ReaderT AssistantData IO a }
 	deriving (
@@ -68,6 +69,7 @@ data AssistantData = AssistantData
 	, branchChangeHandle :: BranchChangeHandle
 	, buddyList :: BuddyList
 	, netMessager :: NetMessager
+	, remoteControl :: RemoteControl
 	}
 
 newAssistantData :: ThreadState -> DaemonStatusHandle -> IO AssistantData
@@ -86,6 +88,7 @@ newAssistantData st dstatus = AssistantData
 	<*> newBranchChangeHandle
 	<*> newBuddyList
 	<*> newNetMessager
+	<*> newRemoteControl
 
 runAssistant :: AssistantData -> Assistant a -> IO a
 runAssistant d a = runReaderT (mkAssistant a) d
diff --git a/Assistant/RemoteControl.hs b/Assistant/RemoteControl.hs
new file mode 100644
index 0000000..86d13cc
--- /dev/null
+++ b/Assistant/RemoteControl.hs
@@ -0,0 +1,21 @@
+{- git-annex assistant RemoteDaemon control
+ -
+ - Copyright 2014 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Assistant.RemoteControl (
+	sendRemoteControl,
+	RemoteDaemon.Consumed(..)
+) where
+
+import Assistant.Common
+import qualified RemoteDaemon.Types as RemoteDaemon
+
+import Control.Concurrent
+
+sendRemoteControl :: RemoteDaemon.Consumed -> Assistant ()
+sendRemoteControl msg = do
+	clicker <- getAssistant remoteControl
+	liftIO $ writeChan clicker msg
diff --git a/Assistant/Sync.hs b/Assistant/Sync.hs
index fc95419..c748f6e 100644
--- a/Assistant/Sync.hs
+++ b/Assistant/Sync.hs
@@ -15,6 +15,7 @@ import Assistant.Alert
 import Assistant.Alert.Utility
 import Assistant.DaemonStatus
 import Assistant.ScanRemotes
+import Assistant.RemoteControl
 import qualified Command.Sync
 import Utility.Parallel
 import qualified Git
@@ -258,6 +259,7 @@ changeSyncable Nothing enable = do
 changeSyncable (Just r) True = do
 	liftAnnex $ changeSyncFlag r True
 	syncRemote r
+	sendRemoteControl RELOAD
 changeSyncable (Just r) False = do
 	liftAnnex $ changeSyncFlag r False
 	updateSyncRemotes
diff --git a/Assistant/Threads/NetWatcher.hs b/Assistant/Threads/NetWatcher.hs
index 0b00964..912893b 100644
--- a/Assistant/Threads/NetWatcher.hs
+++ b/Assistant/Threads/NetWatcher.hs
@@ -15,6 +15,7 @@ import Assistant.Sync
 import Utility.ThreadScheduler
 import qualified Types.Remote as Remote
 import Assistant.DaemonStatus
+import Assistant.RemoteControl
 import Utility.NotificationBroadcaster
 
 #if WITH_DBUS
@@ -44,8 +45,9 @@ netWatcherThread = thread noop
  - while (despite the local network staying up), are synced with
  - periodically.
  -
- - Note that it does not call notifyNetMessagerRestart, because
- - it doesn't know that the network has changed.
+ - Note that it does not call notifyNetMessagerRestart, or
+ - signal the RemoteControl, because it doesn't know that the
+ - network has changed.
  -}
 netWatcherFallbackThread :: NamedThread
 netWatcherFallbackThread = namedThread "NetWatcherFallback" $
@@ -69,8 +71,10 @@ dbusThread = do
 		)
 	handleconn = do
 		debug ["detected network connection"]
+		sendRemoteControl PAUSE
 		notifyNetMessagerRestart
 		handleConnection
+		sendRemoteControl RESUME
 	onerr e _ = do
 		liftAnnex $
 			warning $ "lost dbus connection; falling back to polling (" ++ show e ++ ")"
diff --git a/Assistant/Threads/RemoteControl.hs b/Assistant/Threads/RemoteControl.hs
new file mode 100644
index 0000000..b67b0e0
--- /dev/null
+++ b/Assistant/Threads/RemoteControl.hs
@@ -0,0 +1,80 @@
+{- git-annex assistant communication with remotedaemon
+ -
+ - Copyright 2014 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Assistant.Threads.RemoteControl where
+
+import Assistant.Common
+import RemoteDaemon.Types
+import Config.Files
+import Utility.Batch
+import Utility.SimpleProtocol
+import Assistant.Alert
+import Assistant.Alert.Utility
+import Assistant.DaemonStatus
+
+import Control.Concurrent
+import Control.Concurrent.Async

(Diff truncated)
fix STOP
diff --git a/RemoteDaemon/Core.hs b/RemoteDaemon/Core.hs
index cd4a0aa..a220e58 100644
--- a/RemoteDaemon/Core.hs
+++ b/RemoteDaemon/Core.hs
@@ -29,8 +29,6 @@ runForeground = do
 	ichan <- newChan :: IO (Chan Consumed)
 	ochan <- newChan :: IO (Chan Emitted)
 
-	void $ async $ controller ichan ochan
-
 	let reader = forever $ do
 		l <- getLine
 		case parseMessage l of
@@ -40,18 +38,18 @@ runForeground = do
 		msg <- readChan ochan
 		putStrLn $ unwords $ formatMessage msg
 		hFlush stdout
+	let controller = runController ichan ochan
 	
-	-- If the reader or writer fails, for example because stdin/stdout
-	-- gets closed, kill the other one, and throw an exception which
-	-- will take down the daemon.
-	void $ concurrently reader writer
+	-- If any thread fails, the rest will be killed.
+	void $ tryIO $
+		reader `concurrently` writer `concurrently` controller
 
 type RemoteMap = M.Map Git.Repo (IO (), Chan Consumed)
 
 -- Runs the transports, dispatching messages to them, and handling
 -- the main control messages.
-controller :: Chan Consumed -> Chan Emitted -> IO ()
-controller ichan ochan = do
+runController :: Chan Consumed -> Chan Emitted -> IO ()
+runController ichan ochan = do
 	h <- genTransportHandle
 	m <- genRemoteMap h ochan
 	startrunning m
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index ad41fa4..6b8e064 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -160,8 +160,6 @@ No pushing is done for CHANGED, since git handles ssh natively.
 
 TODO:
 
-* It already detects changes and pulls, but it then dies with a protocol
-  error.
 * Remote system might not be available. Find a smart way to detect it,
   ideally w/o generating network traffic. One way might be to check
   if the ssh connection caching control socket exists, for example.

cleaned up AnnexState handling in transports
diff --git a/Config.hs b/Config.hs
index 10d4fd1..3264426 100644
--- a/Config.hs
+++ b/Config.hs
@@ -32,7 +32,10 @@ getConfigMaybe (ConfigKey key) = fromRepo $ Git.Config.getMaybe key
 setConfig :: ConfigKey -> String -> Annex ()
 setConfig (ConfigKey key) value = do
 	inRepo $ Git.Command.run [Param "config", Param key, Param value]
-	Annex.changeGitRepo =<< inRepo Git.Config.reRead
+	reloadConfig
+
+reloadConfig :: Annex ()
+reloadConfig = Annex.changeGitRepo =<< inRepo Git.Config.reRead
 
 {- Unsets a git config setting. (Leaves it in state currently.) -}
 unsetConfig :: ConfigKey -> Annex ()
diff --git a/RemoteDaemon/Common.hs b/RemoteDaemon/Common.hs
new file mode 100644
index 0000000..29aeb00
--- /dev/null
+++ b/RemoteDaemon/Common.hs
@@ -0,0 +1,42 @@
+{- git-remote-daemon utilities
+ -
+ - Copyright 2014 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module RemoteDaemon.Common
+	( liftAnnex
+	, inLocalRepo
+	, checkNewShas
+	) where
+
+import qualified Annex
+import Common.Annex
+import RemoteDaemon.Types
+import qualified Git
+import Annex.CatFile
+
+import Control.Concurrent
+
+-- Runs an Annex action. Long-running actions should be avoided,
+-- since only one liftAnnex can be running at a time, amoung all
+-- transports.
+liftAnnex :: TransportHandle -> Annex a -> IO a
+liftAnnex (TransportHandle _ annexstate) a = do
+	st <- takeMVar annexstate
+	(r, st') <- Annex.run st a
+	putMVar annexstate st'
+	return r
+
+inLocalRepo :: TransportHandle -> (Git.Repo -> IO a) -> IO a
+inLocalRepo (TransportHandle g _) a = a g
+
+-- Check if any of the shas are actally new in the local git repo,
+-- to avoid unnecessary fetching.
+checkNewShas :: TransportHandle -> [Git.Sha] -> IO Bool
+checkNewShas transporthandle = check
+  where
+	check [] = return True
+	check (r:rs) = maybe (check rs) (const $ return False)
+		=<< liftAnnex transporthandle (catObjectDetails r)
diff --git a/RemoteDaemon/Core.hs b/RemoteDaemon/Core.hs
index 8960bf8..cd4a0aa 100644
--- a/RemoteDaemon/Core.hs
+++ b/RemoteDaemon/Core.hs
@@ -10,15 +10,17 @@ module RemoteDaemon.Core (runForeground) where
 import qualified Annex
 import Common
 import Types.GitConfig
+import RemoteDaemon.Common
 import RemoteDaemon.Types
 import RemoteDaemon.Transport
 import qualified Git
 import qualified Git.Types as Git
 import qualified Git.CurrentRepo
 import Utility.SimpleProtocol
+import Config
 
 import Control.Concurrent.Async
-import Control.Concurrent.Chan
+import Control.Concurrent
 import Network.URI
 import qualified Data.Map as M
 
@@ -50,36 +52,38 @@ type RemoteMap = M.Map Git.Repo (IO (), Chan Consumed)
 -- the main control messages.
 controller :: Chan Consumed -> Chan Emitted -> IO ()
 controller ichan ochan = do
-	m <- getRemoteMap ochan
+	h <- genTransportHandle
+	m <- genRemoteMap h ochan
 	startrunning m
-	go False m
+	go h False m
   where
-	go paused m = do
+	go h paused m = do
 		cmd <- readChan ichan
 		case cmd of
 			RELOAD -> do
-				m' <- getRemoteMap ochan
+				liftAnnex h reloadConfig
+				m' <- genRemoteMap h ochan
 				let common = M.intersection m m'
 				let new = M.difference m' m
 				let old = M.difference m m'
 				stoprunning old
 				unless paused $
 					startrunning new
-				go paused (M.union common new)
+				go h paused (M.union common new)
 			PAUSE -> do
 				stoprunning m
-				go True m
+				go h True m
 			RESUME -> do
 				when paused $
 					startrunning m
-				go False m
+				go h False m
 			STOP -> exitSuccess
 			-- All remaining messages are sent to
 			-- all Transports.
 			msg -> do
 				unless paused $
 					forM_ chans (`writeChan` msg)
-				go paused m
+				go h paused m
 	  where
 		chans = map snd (M.elems m)
 
@@ -90,17 +94,12 @@ controller ichan ochan = do
 	stoprunning m = forM_ (M.elems m) stoprunning'
 	stoprunning' (_, c) = writeChan c STOP
 
-getRemoteMap :: Chan Emitted -> IO RemoteMap
-getRemoteMap ochan = do
-	annexstate <- Annex.new =<< Git.CurrentRepo.get
-	genRemoteMap annexstate ochan
-
 -- Generates a map with a transport for each supported remote in the git repo,
 -- except those that have annex.sync = false
-genRemoteMap :: Annex.AnnexState -> Chan Emitted -> IO RemoteMap
-genRemoteMap annexstate ochan = M.fromList . catMaybes <$> mapM gen rs
+genRemoteMap :: TransportHandle -> Chan Emitted -> IO RemoteMap
+genRemoteMap h@(TransportHandle g _) ochan =
+	M.fromList . catMaybes <$> mapM gen (Git.remotes g)
   where
-	rs = Git.remotes (Annex.repo annexstate)
 	gen r = case Git.location r of
 		Git.Url u -> case M.lookup (uriScheme u) remoteTransports of
 			Just transport
@@ -108,7 +107,13 @@ genRemoteMap annexstate ochan = M.fromList . catMaybes <$> mapM gen rs
 					ichan <- newChan :: IO (Chan Consumed)
 					return $ Just
 						( r
-						, (transport r (Git.repoDescribe r) annexstate ichan ochan, ichan)
+						, (transport r (Git.repoDescribe r) h ichan ochan, ichan)
 						)
 			_ -> return Nothing
 		_ -> return Nothing
+
+genTransportHandle :: IO TransportHandle
+genTransportHandle = do
+	annexstate <- newMVar =<< Annex.new =<< Git.CurrentRepo.get
+	g <- Annex.repo <$> readMVar annexstate
+	return $ TransportHandle g annexstate
diff --git a/RemoteDaemon/Transport/Ssh.hs b/RemoteDaemon/Transport/Ssh.hs
index 8f4d007..557a3dc 100644
--- a/RemoteDaemon/Transport/Ssh.hs
+++ b/RemoteDaemon/Transport/Ssh.hs
@@ -8,13 +8,11 @@
 module RemoteDaemon.Transport.Ssh (transport) where
 
 import Common.Annex
-import qualified Annex
 import RemoteDaemon.Types
-import qualified RemoteDaemon.Transport.Ssh.Types as SshRemote
+import RemoteDaemon.Common
 import Remote.Helper.Ssh
+import qualified RemoteDaemon.Transport.Ssh.Types as SshRemote
 import Utility.SimpleProtocol
-import qualified Git
-import Annex.CatFile
 import Git.Command
 
 import Control.Concurrent.Chan
@@ -22,13 +20,12 @@ import Control.Concurrent.Async
 import System.Process (std_in, std_out)
 
 transport :: Transport
-transport r remotename annexstate ichan ochan = Annex.eval annexstate $ do
-	v <- git_annex_shell r "notifychanges" [] []
+transport r remotename transporthandle ichan ochan = do
+	v <- liftAnnex transporthandle $ git_annex_shell r "notifychanges" [] []
 	case v of
 		Nothing -> noop

(Diff truncated)
clarify
diff --git a/doc/design/git-remote-daemon.mdwn b/doc/design/git-remote-daemon.mdwn
index db56bd6..5599a6f 100644
--- a/doc/design/git-remote-daemon.mdwn
+++ b/doc/design/git-remote-daemon.mdwn
@@ -114,6 +114,10 @@ the webapp.
   Indicates that configs have changed. Daemon should reload .git/config
   and/or restart.
 
+  Possible config changes include adding a new remote, removing a remote,
+  or setting `remote.<name>.annex-sync` to configure whether to sync with a
+  particular remote.
+
 * `STOP`
 
   Shut down git-remote-daemon

Added a comment: Encrypt with pub or sub?
diff --git a/doc/encryption/comment_2_f19c9bb519a7017f0731fd0e8780ed74._comment b/doc/encryption/comment_2_f19c9bb519a7017f0731fd0e8780ed74._comment
new file mode 100644
index 0000000..bf43303
--- /dev/null
+++ b/doc/encryption/comment_2_f19c9bb519a7017f0731fd0e8780ed74._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="https://openid.stackexchange.com/user/e65e6d0e-58ba-41de-84cc-1f2ba54cf574"
+ nickname="Mica Semrick"
+ subject="Encrypt with pub or sub?"
+ date="2014-04-08T03:56:36Z"
+ content="""
+Forgive me, I'm a bit new to PGP.
+
+I do: 
+
+    $ gpg --list-keys
+    /home/user/.gnupg/pubring.gpg
+    ------------------------------
+    pub   2048R/41363A6A 2014-04-03
+    uid                  A Guy (git-annex key) <A@guy.com>
+    sub   2048R/77998J8TDY 2014-04-03
+
+and see the pub and the sub key.
+
+When I init a new special remote and want encryption, should I give the init command the pub or the sub key? Or does git annex sort that out itself?
+
+"""]]

removed
diff --git a/doc/encryption/comment_2_0bd22cec899dd5d1e4d090b34c5ec1eb._comment b/doc/encryption/comment_2_0bd22cec899dd5d1e4d090b34c5ec1eb._comment
deleted file mode 100644
index 4436ccc..0000000
--- a/doc/encryption/comment_2_0bd22cec899dd5d1e4d090b34c5ec1eb._comment
+++ /dev/null
@@ -1,22 +0,0 @@
-[[!comment format=mdwn
- username="https://openid.stackexchange.com/user/e65e6d0e-58ba-41de-84cc-1f2ba54cf574"
- nickname="Mica Semrick"
- subject="Encrypt with pub or sub?"
- date="2014-04-08T03:47:25Z"
- content="""
-Forgive me, I'm a bit new to PGP.
-
- I do:
-```
-$ gpg --list-keys
-/home/users/.gnupg/pubring.gpg
-------------------------------
-pub   2048R/3339656A 2014-04-03
-uid                  Me (git-annex key) <me@example.com>
-sub   2048R/774B0ET4 2014-04-03
-
-```
-and see the `pub` and the `sub` key.
-
-When I `init` a new special remote and want encryption, should I give the `init` command the `pub` or the `sub` key? Or does git annex sort that out itself?
-"""]]

Added a comment: Encrypt with pub or sub?
diff --git a/doc/encryption/comment_2_0bd22cec899dd5d1e4d090b34c5ec1eb._comment b/doc/encryption/comment_2_0bd22cec899dd5d1e4d090b34c5ec1eb._comment
new file mode 100644
index 0000000..4436ccc
--- /dev/null
+++ b/doc/encryption/comment_2_0bd22cec899dd5d1e4d090b34c5ec1eb._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="https://openid.stackexchange.com/user/e65e6d0e-58ba-41de-84cc-1f2ba54cf574"
+ nickname="Mica Semrick"
+ subject="Encrypt with pub or sub?"
+ date="2014-04-08T03:47:25Z"
+ content="""
+Forgive me, I'm a bit new to PGP.
+
+ I do:
+```
+$ gpg --list-keys
+/home/users/.gnupg/pubring.gpg
+------------------------------
+pub   2048R/3339656A 2014-04-03
+uid                  Me (git-annex key) <me@example.com>
+sub   2048R/774B0ET4 2014-04-03
+
+```
+and see the `pub` and the `sub` key.
+
+When I `init` a new special remote and want encryption, should I give the `init` command the `pub` or the `sub` key? Or does git annex sort that out itself?
+"""]]

Added a comment
diff --git a/doc/bugs/Assistant_having_a_child_git_cat-file_--batch_do_the_same_thing_over_and_over_and_using_a_lot_of_memory/comment_9_5f4444f03cbebaa44628288095383679._comment b/doc/bugs/Assistant_having_a_child_git_cat-file_--batch_do_the_same_thing_over_and_over_and_using_a_lot_of_memory/comment_9_5f4444f03cbebaa44628288095383679._comment
new file mode 100644
index 0000000..0938314
--- /dev/null
+++ b/doc/bugs/Assistant_having_a_child_git_cat-file_--batch_do_the_same_thing_over_and_over_and_using_a_lot_of_memory/comment_9_5f4444f03cbebaa44628288095383679._comment
@@ -0,0 +1,89 @@
+[[!comment format=mdwn
+ username="http://johan.kiviniemi.name/"
+ nickname="Johan"
+ subject="comment 9"
+ date="2014-04-07T22:55:12Z"
+ content="""
+[[!toggle id=\"excerpt\" text=\"The full log excerpt\"]] which includes the sync from the client and the final messages after the cat-file loop ended and things stabilized (but a memory leak of 30 MB in the git-annex assistant process remained).
+
+[[!toggleable id=\"excerpt\" text=\"\"\"
+    [2014-04-04 10:55:00 EEST] main: starting assistant version 5.20140402
+    
+    
+    
+    [2014-04-07 23:21:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"git-annex\"]
+    [2014-04-07 23:21:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+    [2014-04-07 23:21:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..20d1f5538f6aa430f29ef938f6db045f5a69425d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..b402a6e7b9268e25dbd9c6a027f4a5258993980d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..7b18a191d58d779aab5789b923adb09863938ffe\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"ls-tree\",\"--full-tree\",\"-z\",\"--\",\"refs/heads/git-annex\",\"uuid.log\",\"remote.log\",\"trust.log\",\"group.log\",\"numcopies.log\",\"schedule.log\",\"preferred-content.log\",\"required-content.log\",\"group-preferred-content.log\"]
+    [2014-04-07 23:21:52 EEST] TransferWatcher: transfer starting: Download UUID \"86e07a59-8bba-4878-8d0b-5dfe8c6366c4\" SHA256E-s6--5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03 Nothing
+    [2014-04-07 23:21:52 EEST] read: git [\"config\",\"--null\",\"--list\"]
+    [2014-04-07 23:21:52 EEST] TransferWatcher: transfer starting: Download UUID \"86e07a59-8bba-4878-8d0b-5dfe8c6366c4\" test/hello Nothing
+    [2014-04-07 23:21:52 EEST] read: git [\"config\",\"--null\",\"--list\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"git-annex\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..20d1f5538f6aa430f29ef938f6db045f5a69425d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..4deec8203e0baf7bb5b7d5d868d82439261ab3bc\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..b402a6e7b9268e25dbd9c6a027f4a5258993980d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..7b18a191d58d779aab5789b923adb09863938ffe\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:52 EEST] feed: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-index\",\"-z\",\"--index-info\"]
+    [2014-04-07 23:21:52 EEST] TransferWatcher: transfer finishing: Transfer {transferDirection = Download, transferUUID = UUID \"86e07a59-8bba-4878-8d0b-5dfe8c6366c4\", transferKey = Key {keyName = \"5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03\", keyBackendName = \"SHA256E\", keySize = Just 6, keyMtime = Nothing}}
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"diff-index\",\"--raw\",\"-z\",\"-r\",\"--no-renames\",\"-l0\",\"--cached\",\"4deec8203e0baf7bb5b7d5d868d82439261ab3bc\"]
+    [2014-04-07 23:21:52 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"4deec8203e0baf7bb5b7d5d868d82439261ab3bc..refs/heads/git-annex\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:21:52 EEST] call: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-ref\",\"refs/heads/git-annex\",\"4deec8203e0baf7bb5b7d5d868d82439261ab3bc\"]
+    [2014-04-07 23:22:08 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"ls-tree\",\"--full-tree\",\"-z\",\"--\",\"refs/heads/git-annex\",\"uuid.log\",\"remote.log\",\"trust.log\",\"group.log\",\"numcopies.log\",\"schedule.log\",\"preferred-content.log\",\"required-content.log\",\"group-preferred-content.log\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"symbolic-ref\",\"HEAD\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"refs/heads/master\"]
+    [2014-04-07 23:24:24 EEST] Merger: merging refs/heads/synced/master into refs/heads/master
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/master\"]
+    [2014-04-07 23:24:24 EEST] call: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"merge\",\"--no-edit\",\"refs/heads/synced/master\"]
+    Updating 645e474..8406809
+    Fast-forward
+     test/hello |    1 +
+     1 file changed, 1 insertion(+)
+     create mode 120000 test/hello
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"git-annex\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..4deec8203e0baf7bb5b7d5d868d82439261ab3bc\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..2e0884d9c8859339855ceee396b9ea9ae05865b4\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..b402a6e7b9268e25dbd9c6a027f4a5258993980d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..7b18a191d58d779aab5789b923adb09863938ffe\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:24:24 EEST] chat: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"hash-object\",\"-w\",\"--stdin-paths\",\"--no-filters\"]
+    [2014-04-07 23:24:24 EEST] feed: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-index\",\"-z\",\"--index-info\"]
+    [2014-04-07 23:24:24 EEST] feed: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-index\",\"-z\",\"--index-info\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"diff-index\",\"--raw\",\"-z\",\"-r\",\"--no-renames\",\"-l0\",\"--cached\",\"2e0884d9c8859339855ceee396b9ea9ae05865b4\"]
+    [2014-04-07 23:24:24 EEST] chat: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"hash-object\",\"-t\",\"blob\",\"-w\",\"--stdin\",\"--no-filters\"]
+    [2014-04-07 23:24:24 EEST] feed: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-index\",\"-z\",\"--index-info\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"diff-index\",\"--raw\",\"-z\",\"-r\",\"--no-renames\",\"-l0\",\"--cached\",\"refs/heads/git-annex\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"write-tree\"]
+    [2014-04-07 23:24:24 EEST] chat: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"commit-tree\",\"0bd4352b4008165d356bc9b1250bdb456c675175\",\"-p\",\"refs/heads/git-annex\",\"-p\",\"2e0884d9c8859339855ceee396b9ea9ae05865b4\"]
+    [2014-04-07 23:24:24 EEST] call: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-ref\",\"refs/heads/git-annex\",\"214ed317536695b91c8dd5bed059c46c11ad00be\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"ls-tree\",\"--full-tree\",\"-z\",\"--\",\"refs/heads/git-annex\",\"uuid.log\",\"remote.log\",\"trust.log\",\"group.log\",\"numcopies.log\",\"schedule.log\",\"preferred-content.log\",\"required-content.log\",\"group-preferred-content.log\"]
+    [2014-04-07 23:24:24 EEST] Watcher: add symlink test/hello
+    [2014-04-07 23:24:24 EEST] chat: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"hash-object\",\"-t\",\"blob\",\"-w\",\"--stdin\",\"--no-filters\"]
+    [2014-04-07 23:24:24 EEST] Committer: committing 1 changes
+    [2014-04-07 23:24:24 EEST] Committer: Committing changes to git
+    [2014-04-07 23:24:24 EEST] feed: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"update-index\",\"-z\",\"--index-info\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"symbolic-ref\",\"HEAD\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/master\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"write-tree\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"rev-parse\",\"84068090af4bcd3d24f16d865ac07b0478f20ada:\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"symbolic-ref\",\"HEAD\"]
+    [2014-04-07 23:24:24 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"refs/heads/master\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"git-annex\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..214ed317536695b91c8dd5bed059c46c11ad00be\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..2e0884d9c8859339855ceee396b9ea9ae05865b4\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..b402a6e7b9268e25dbd9c6a027f4a5258993980d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..7b18a191d58d779aab5789b923adb09863938ffe\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"ls-tree\",\"--full-tree\",\"-z\",\"--\",\"refs/heads/git-annex\",\"uuid.log\",\"remote.log\",\"trust.log\",\"group.log\",\"numcopies.log\",\"schedule.log\",\"preferred-content.log\",\"required-content.log\",\"group-preferred-content.log\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"git-annex\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..214ed317536695b91c8dd5bed059c46c11ad00be\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..2e0884d9c8859339855ceee396b9ea9ae05865b4\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..b402a6e7b9268e25dbd9c6a027f4a5258993980d\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:30:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"log\",\"refs/heads/git-annex..7b18a191d58d779aab5789b923adb09863938ffe\",\"--oneline\",\"-n1\"]
+    [2014-04-07 23:31:13 EEST] read: git [\"--git-dir=/storage/sarjat/annex-sarjat/.git\",\"--work-tree=/storage/sarjat/annex-sarjat\",\"ls-tree\",\"--full-tree\",\"-z\",\"--\",\"refs/heads/git-annex\",\"uuid.log\",\"remote.log\",\"trust.log\",\"group.log\",\"numcopies.log\",\"schedule.log\",\"preferred-content.log\",\"required-content.log\",\"group-preferred-content.log\"]
+\"\"\"]]
+"""]]

devblog
diff --git a/doc/devblog/day_148__too_many_documents.mdwn b/doc/devblog/day_148__too_many_documents.mdwn
new file mode 100644
index 0000000..3cb5e5b
--- /dev/null
+++ b/doc/devblog/day_148__too_many_documents.mdwn
@@ -0,0 +1,8 @@
+Various bug triage today. Was not good for much after shuffling paper for
+the whole first part of the day, but did get a few little things done.
+
+Re <http://heartbleed.com/>, git-annex does not use OpenSSL itself,
+but when using XMPP, the remote server's key could have been intercepted
+using this new technique. Also, the git-annex autobuilds and this website
+are served over https -- working on generating new https certificates now.
+Be safe out there..

Added a comment
diff --git a/doc/bugs/Assistant_having_a_child_git_cat-file_--batch_do_the_same_thing_over_and_over_and_using_a_lot_of_memory/comment_8_03dd76b01f46a7cc66eddac3e054c8ad._comment b/doc/bugs/Assistant_having_a_child_git_cat-file_--batch_do_the_same_thing_over_and_over_and_using_a_lot_of_memory/comment_8_03dd76b01f46a7cc66eddac3e054c8ad._comment
new file mode 100644
index 0000000..d6aa43d
--- /dev/null
+++ b/doc/bugs/Assistant_having_a_child_git_cat-file_--batch_do_the_same_thing_over_and_over_and_using_a_lot_of_memory/comment_8_03dd76b01f46a7cc66eddac3e054c8ad._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="http://johan.kiviniemi.name/"
+ nickname="Johan"
+ subject="comment 8"
+ date="2014-04-07T22:48:18Z"
+ content="""
+There are no commits in `master` or `git-annex` that have the word conflict in the description.
+"""]]