diff --git a/Annex.hs b/Annex.hs
--- a/Annex.hs
+++ b/Annex.hs
@@ -37,7 +37,7 @@
 import Common
 import qualified Git
 import qualified Git.Config
-import Annex.Direct.Fixup
+import Annex.Fixup
 import Git.CatFile
 import Git.CheckAttr
 import Git.CheckIgnore
@@ -183,12 +183,13 @@
 	}
 
 {- Makes an Annex state object for the specified git repo.
- - Ensures the config is read, if it was not already. -}
+ - Ensures the config is read, if it was not already, and performs
+ - any necessary git repo fixups. -}
 new :: Git.Repo -> IO AnnexState
 new r = do
 	r' <- Git.Config.read =<< Git.relPath r
 	let c = extractGitConfig r'
-	newState c <$> if annexDirect c then fixupDirect r' else return r'
+	newState c <$> fixupRepo r' c
 
 {- Performs an action in the Annex monad from a starting state,
  - returning a new state. -}
diff --git a/Annex/Direct.hs b/Annex/Direct.hs
--- a/Annex/Direct.hs
+++ b/Annex/Direct.hs
@@ -406,7 +406,25 @@
 	Annex.changeGitConfig $ \c -> c { annexDirect = wantdirect }
   where
 	val = Git.Config.boolConfig wantdirect
-	setbare = setConfig (ConfigKey Git.Config.coreBare) val
+	coreworktree = ConfigKey "core.worktree"
+	indirectworktree = ConfigKey "core.indirect-worktree"
+	setbare = do
+		-- core.worktree is not compatable with
+		-- core.bare; git does not allow both to be set, so
+		-- unset it when enabling direct mode, caching in
+		-- core.indirect-worktree
+		if wantdirect
+			then moveconfig coreworktree indirectworktree
+			else moveconfig indirectworktree coreworktree
+		setConfig (ConfigKey Git.Config.coreBare) val
+	moveconfig src dest = do
+		v <- getConfigMaybe src
+		case v of
+			Nothing -> noop
+			Just wt -> do
+				unsetConfig src
+				setConfig dest wt
+				reloadConfig
 
 {- Since direct mode sets core.bare=true, incoming pushes could change
  - the currently checked out branch. To avoid this problem, HEAD
diff --git a/Annex/Direct/Fixup.hs b/Annex/Direct/Fixup.hs
deleted file mode 100644
--- a/Annex/Direct/Fixup.hs
+++ /dev/null
@@ -1,31 +0,0 @@
-{- git-annex direct mode guard fixup
- -
- - Copyright 2013 Joey Hess <id@joeyh.name>
- -
- - Licensed under the GNU GPL version 3 or higher.
- -}
-
-module Annex.Direct.Fixup where
-
-import Git.Types
-import Git.Config
-import qualified Git.Construct as Construct
-import Utility.Path
-import Utility.SafeCommand
-
-{- Direct mode repos have core.bare=true, but are not really bare.
- - Fix up the Repo to be a non-bare repo, and arrange for git commands
- - run by git-annex to be passed parameters that override this setting. -}
-fixupDirect :: Repo -> IO Repo
-fixupDirect r@(Repo { location = l@(Local { gitdir = d, worktree = Nothing }) }) = do
-	let r' = r
-		{ location = l { worktree = Just (parentDir d) }
-		, gitGlobalOpts = gitGlobalOpts r ++
-			[ Param "-c"
-			, Param $ coreBare ++ "=" ++ boolConfig False
-			]
-		}
-	-- Recalc now that the worktree is correct.
-	rs' <- Construct.fromRemotes r'
-	return $ r' { remotes = rs' }
-fixupDirect r = return r
diff --git a/Annex/Fixup.hs b/Annex/Fixup.hs
new file mode 100644
--- /dev/null
+++ b/Annex/Fixup.hs
@@ -0,0 +1,92 @@
+{- git-annex repository fixups
+ -
+ - Copyright 2013, 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Annex.Fixup where
+
+import Git.Types
+import Git.Config
+import Types.GitConfig
+import qualified Git.Construct as Construct
+import Utility.Path
+import Utility.SafeCommand
+import Utility.Directory
+import Utility.PosixFiles
+import Utility.Exception
+
+import System.IO
+import System.FilePath
+import System.Directory
+import Data.List
+import Control.Monad
+import Control.Monad.IfElse
+import qualified Data.Map as M
+
+fixupRepo :: Repo -> GitConfig -> IO Repo
+fixupRepo r c = do
+	r' <- fixupSubmodule r c
+	if annexDirect c
+		then fixupDirect r'
+		else return r'
+
+{- Direct mode repos have core.bare=true, but are not really bare.
+ - Fix up the Repo to be a non-bare repo, and arrange for git commands
+ - run by git-annex to be passed parameters that override this setting. -}
+fixupDirect :: Repo -> IO Repo
+fixupDirect r@(Repo { location = l@(Local { gitdir = d, worktree = Nothing }) }) = do
+	let r' = r
+		{ location = l { worktree = Just (parentDir d) }
+		, gitGlobalOpts = gitGlobalOpts r ++
+			[ Param "-c"
+			, Param $ coreBare ++ "=" ++ boolConfig False
+			]
+		}
+	-- Recalc now that the worktree is correct.
+	rs' <- Construct.fromRemotes r'
+	return $ r' { remotes = rs' }
+fixupDirect r = return r
+
+{- Submodules have their gitdir containing ".git/modules/", and
+ - have core.worktree set, and also have a .git file in the top
+ - of the repo. 
+ -
+ - We need to unset core.worktree, and change the .git file into a
+ - symlink to the git directory. This way, annex symlinks will be
+ - of the usual .git/annex/object form, and will consistently work
+ - whether a repo is used as a submodule or not, and wheverever the
+ - submodule is mounted.
+ -
+ - When the filesystem doesn't support symlinks, we cannot make .git
+ - into a symlink. But we don't need too, since the repo will use direct
+ - mode, In this case, we merely adjust the Repo so that
+ - symlinks to objects that get checked in will be in the right form.
+ -}
+fixupSubmodule :: Repo -> GitConfig -> IO Repo
+fixupSubmodule r@(Repo { location = l@(Local { worktree = Just w, gitdir = d }) }) c
+	| needsSubmoduleFixup r = do
+		when (coreSymlinks c) $
+			replacedotgit
+				`catchNonAsync` \_e -> hPutStrLn stderr
+					"warning: unable to convert submodule to form that will work with git-annex"
+		return $ r
+			{ location = if coreSymlinks c
+				then l { gitdir = dotgit }
+				else l
+			, config = M.delete "core.worktree" (config r)
+			}
+  where
+	dotgit = w </> ".git"
+	replacedotgit = whenM (doesFileExist dotgit) $ do
+		nukeFile dotgit
+		createSymbolicLink (w </> d) dotgit
+		maybe (error "unset core.worktree failed") (\_ -> return ())
+			=<< Git.Config.unset "core.worktree" r
+fixupSubmodule r _ = return r
+
+needsSubmoduleFixup :: Repo -> Bool
+needsSubmoduleFixup (Repo { location = (Local { worktree = Just _, gitdir = d }) }) =
+	(".git" </> "modules") `isInfixOf` d
+needsSubmoduleFixup _ = False
diff --git a/Annex/LockFile.hs b/Annex/LockFile.hs
--- a/Annex/LockFile.hs
+++ b/Annex/LockFile.hs
@@ -1,6 +1,6 @@
 {- git-annex lock files.
  -
- - Copyright 2012, 2014 Joey Hess <id@joeyh.name>
+ - Copyright 2012-2015 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU GPL version 3 or higher.
  -}
@@ -12,6 +12,7 @@
 	unlockFile,
 	getLockPool,
 	withExclusiveLock,
+	tryExclusiveLock,
 ) where
 
 import Common.Annex
@@ -70,3 +71,21 @@
 #else
 	lock _mode = waitToLock . lockExclusive
 #endif
+
+{- Tries to take an exclusive lock and run an action. If the lock is
+ - already held, returns Nothing. -}
+tryExclusiveLock :: (Git.Repo -> FilePath) -> Annex a -> Annex (Maybe a)
+tryExclusiveLock getlockfile a = do
+	lockfile <- fromRepo getlockfile
+	createAnnexDirectory $ takeDirectory lockfile
+	mode <- annexFileMode
+	bracketIO (lock mode lockfile) unlock go
+  where
+#ifndef mingw32_HOST_OS
+	lock mode = noUmask mode . tryLockExclusive (Just mode)
+#else
+	lock _mode = lockExclusive
+#endif
+	unlock = maybe noop dropLock
+	go Nothing = return Nothing
+	go (Just _) = Just <$> a
diff --git a/Annex/Path.hs b/Annex/Path.hs
--- a/Annex/Path.hs
+++ b/Annex/Path.hs
@@ -17,9 +17,10 @@
  - 
  - getExecutablePath is available since ghc 7.4.2. On OSs it supports
  - well, it returns the complete path to the program. But, on other OSs,
- - it might return just the basename.
+ - it might return just the basename. Fall back to reading the programFile,
+ - or searching for the command name in PATH.
  -}
-programPath :: IO (Maybe FilePath)
+programPath :: IO FilePath
 programPath = do
 #if MIN_VERSION_base(4,6,0)
 	exe <- getExecutablePath
@@ -29,6 +30,4 @@
 #else
 	p <- readProgramFile
 #endif
-	-- In case readProgramFile returned just the command name,
-	-- fall back to finding it in PATH.
-	searchPath p
+	maybe cannotFindProgram return =<< searchPath p
diff --git a/Annex/Ssh.hs b/Annex/Ssh.hs
--- a/Annex/Ssh.hs
+++ b/Annex/Ssh.hs
@@ -31,7 +31,7 @@
 import qualified Git
 import qualified Git.Url
 import Config
-import Config.Files
+import Annex.Path
 import Utility.Env
 import Types.CleanupActions
 import Annex.Index (addGitEnv)
@@ -273,7 +273,7 @@
 			case msockfile of
 				Nothing -> return g
 				Just sockfile -> do
-					command <- liftIO readProgramFile
+					command <- liftIO programPath
 					prepSocket sockfile
 					let val = toSshOptionsEnv $ concat
 						[ sshConnectionCachingParams sockfile
diff --git a/Assistant.hs b/Assistant.hs
--- a/Assistant.hs
+++ b/Assistant.hs
@@ -56,6 +56,7 @@
 import Utility.LogFile
 #ifdef mingw32_HOST_OS
 import Utility.Env
+import Annex.Path
 import Config.Files
 import System.Environment (getArgs)
 #endif
@@ -104,7 +105,7 @@
 			( liftIO $ withFile devNull WriteMode $ \nullh -> do
 				loghandle <- openLog logfile
 				e <- getEnvironment
-				cmd <- readProgramFile
+				cmd <- programPath
 				ps <- getArgs
 				(_, _, _, pid) <- createProcess (proc cmd ps)
 					{ env = Just (addEntry flag "1" e)
diff --git a/Assistant/Repair.hs b/Assistant/Repair.hs
--- a/Assistant/Repair.hs
+++ b/Assistant/Repair.hs
@@ -19,7 +19,7 @@
 import Logs.FsckResults
 import Annex.UUID
 import Utility.Batch
-import Config.Files
+import Annex.Path
 import Assistant.Sync
 import Assistant.Alert
 import Assistant.DaemonStatus
@@ -105,7 +105,7 @@
 		return ok
 	
 	backgroundfsck params = liftIO $ void $ async $ do
-		program <- readProgramFile
+		program <- programPath
 		batchCommand program (Param "fsck" : params)
 
 {- Detect when a git lock file exists and has no git process currently
diff --git a/Assistant/Restart.hs b/Assistant/Restart.hs
--- a/Assistant/Restart.hs
+++ b/Assistant/Restart.hs
@@ -19,9 +19,9 @@
 import Utility.PID
 import qualified Git.Construct
 import qualified Git.Config
-import Config.Files
 import qualified Annex
 import qualified Git
+import Annex.Path
 
 import Control.Concurrent
 #ifndef mingw32_HOST_OS
@@ -110,7 +110,7 @@
  -}
 startAssistant :: FilePath -> IO ()
 startAssistant repo = void $ forkIO $ do
-	program <- readProgramFile
+	program <- programPath
 	(_, _, _, pid) <- 
 		createProcess $
 			(proc program ["assistant"]) { cwd = Just repo }
diff --git a/Assistant/Threads/Cronner.hs b/Assistant/Threads/Cronner.hs
--- a/Assistant/Threads/Cronner.hs
+++ b/Assistant/Threads/Cronner.hs
@@ -15,7 +15,7 @@
 import Assistant.DaemonStatus
 import Utility.NotificationBroadcaster
 import Annex.UUID
-import Config.Files
+import Annex.Path
 import Logs.Schedule
 import Utility.Scheduled
 import Types.ScheduledActivity
@@ -181,7 +181,7 @@
 
 runActivity' :: UrlRenderer -> ScheduledActivity -> Assistant ()
 runActivity' urlrenderer (ScheduledSelfFsck _ d) = do
-	program <- liftIO $ readProgramFile
+	program <- liftIO programPath
 	g <- liftAnnex gitRepo
 	fsckresults <- showFscking urlrenderer Nothing $ tryNonAsync $ do
 		void $ batchCommand program (Param "fsck" : annexFsckParams d)
@@ -196,7 +196,7 @@
 	dispatch Nothing = debug ["skipping remote fsck of uuid without a configured remote", fromUUID u, fromSchedule s]
 	dispatch (Just rmt) = void $ case Remote.remoteFsck rmt of
 		Nothing -> go rmt $ do
-			program <- readProgramFile
+			program <- programPath
 			void $ batchCommand program $ 
 				[ Param "fsck"
 				-- avoid downloading files
diff --git a/Assistant/Threads/RemoteControl.hs b/Assistant/Threads/RemoteControl.hs
--- a/Assistant/Threads/RemoteControl.hs
+++ b/Assistant/Threads/RemoteControl.hs
@@ -9,7 +9,7 @@
 
 import Assistant.Common
 import RemoteDaemon.Types
-import Config.Files
+import Annex.Path
 import Utility.Batch
 import Utility.SimpleProtocol
 import Assistant.Alert
@@ -28,7 +28,7 @@
 
 remoteControlThread :: NamedThread
 remoteControlThread = namedThread "RemoteControl" $ do
-	program <- liftIO readProgramFile
+	program <- liftIO programPath
 	(cmd, params) <- liftIO $ toBatchCommand
 		(program, [Param "remotedaemon"])
 	let p = proc cmd (toCommand params)
diff --git a/Assistant/Threads/SanityChecker.hs b/Assistant/Threads/SanityChecker.hs
--- a/Assistant/Threads/SanityChecker.hs
+++ b/Assistant/Threads/SanityChecker.hs
@@ -39,7 +39,7 @@
 import Assistant.Unused
 import Logs.Unused
 import Logs.Transfer
-import Config.Files
+import Annex.Path
 import Types.Key (keyBackendName)
 import qualified Annex
 #ifdef WITH_WEBAPP
@@ -182,7 +182,7 @@
 	{- Run git-annex unused once per day. This is run as a separate
 	 - process to stay out of the annex monad and so it can run as a
 	 - batch job. -}
-	program <- liftIO readProgramFile
+	program <- liftIO programPath
 	let (program', params') = batchmaker (program, [Param "unused"])
 	void $ liftIO $ boolSystem program' params'
 	{- Invalidate unused keys cache, and queue transfers of all unused
diff --git a/Assistant/Threads/Transferrer.hs b/Assistant/Threads/Transferrer.hs
--- a/Assistant/Threads/Transferrer.hs
+++ b/Assistant/Threads/Transferrer.hs
@@ -11,13 +11,13 @@
 import Assistant.TransferQueue
 import Assistant.TransferSlots
 import Logs.Transfer
-import Config.Files
+import Annex.Path
 import Utility.Batch
 
 {- Dispatches transfers from the queue. -}
 transfererThread :: NamedThread
 transfererThread = namedThread "Transferrer" $ do
-	program <- liftIO readProgramFile
+	program <- liftIO programPath
 	batchmaker <- liftIO getBatchCommandMaker
 	forever $ inTransferSlot program batchmaker $
 		maybe (return Nothing) (uncurry genTransfer)
diff --git a/Assistant/Threads/UpgradeWatcher.hs b/Assistant/Threads/UpgradeWatcher.hs
--- a/Assistant/Threads/UpgradeWatcher.hs
+++ b/Assistant/Threads/UpgradeWatcher.hs
@@ -36,8 +36,7 @@
 		showSuccessfulUpgrade urlrenderer
 	go =<< liftIO upgradeFlagFile
   where
-	go Nothing = debug [ "cannot determine program path" ]
-	go (Just flagfile) = do
+	go flagfile = do
 		mvar <- liftIO $ newMVar InStartupScan
 		changed <- Just <$> asIO2 (changedFile urlrenderer mvar flagfile)
 		let hooks = mkWatchHooks
diff --git a/Assistant/TransferSlots.hs b/Assistant/TransferSlots.hs
--- a/Assistant/TransferSlots.hs
+++ b/Assistant/TransferSlots.hs
@@ -28,7 +28,7 @@
 import qualified Types.Remote as Remote
 import Annex.Content
 import Annex.Wanted
-import Config.Files
+import Annex.Path
 import Utility.Batch
 
 import qualified Data.Map as M 
@@ -284,7 +284,7 @@
 		alterTransferInfo t $ \i -> i { transferPaused = False }
 		liftIO $ throwTo tid ResumeTransfer
 	start info = do
-		program <- liftIO readProgramFile
+		program <- liftIO programPath
 		batchmaker <- liftIO getBatchCommandMaker
 		inImmediateTransferSlot program batchmaker $
 			genTransfer t info
diff --git a/Assistant/Upgrade.hs b/Assistant/Upgrade.hs
--- a/Assistant/Upgrade.hs
+++ b/Assistant/Upgrade.hs
@@ -288,11 +288,8 @@
 {- This is a file that the UpgradeWatcher can watch for modifications to
  - detect when git-annex has been upgraded.
  -}
-upgradeFlagFile :: IO (Maybe FilePath)
-upgradeFlagFile = ifM usingDistribution
-	( Just <$> programFile
-	, programPath
-	)
+upgradeFlagFile :: IO FilePath
+upgradeFlagFile = programPath
 
 {- Sanity check to see if an upgrade is complete and the program is ready
  - to be run. -}
@@ -303,13 +300,10 @@
 		-- Ensure that the program is present, and has no writers,
 		-- and can be run. This should handle distribution
 		-- upgrades, manual upgrades, etc.
-		v <- programPath
-		case v of
-			Nothing -> return False
-			Just program -> do
-				untilM (doesFileExist program <&&> nowriter program) $
-					threadDelaySeconds (Seconds 60)
-				boolSystem program [Param "version"]
+		program <- programPath
+		untilM (doesFileExist program <&&> nowriter program) $
+			threadDelaySeconds (Seconds 60)
+		boolSystem program [Param "version"]
 	)
   where
 	nowriter f = null
diff --git a/Assistant/WebApp/Configurators/Ssh.hs b/Assistant/WebApp/Configurators/Ssh.hs
--- a/Assistant/WebApp/Configurators/Ssh.hs
+++ b/Assistant/WebApp/Configurators/Ssh.hs
@@ -28,7 +28,7 @@
 import Assistant.RemoteControl
 import Types.Creds
 import Assistant.CredPairCache
-import Config.Files
+import Annex.Path
 import Utility.Tmp
 import Utility.FileMode
 import Utility.ThreadScheduler
@@ -381,7 +381,7 @@
 		Just (fromMaybe "" input)
 
 	setupAskPass = do
-		program <- liftIO readProgramFile
+		program <- liftIO programPath
 		v <- getCachedCred login
 		liftIO $ case v of
 			Nothing -> go [passwordprompts 0] Nothing
diff --git a/Assistant/XMPP/Git.hs b/Assistant/XMPP/Git.hs
--- a/Assistant/XMPP/Git.hs
+++ b/Assistant/XMPP/Git.hs
@@ -20,6 +20,7 @@
 import Assistant.Sync
 import qualified Command.Sync
 import qualified Annex.Branch
+import Annex.Path
 import Annex.UUID
 import Logs.UUID
 import Annex.TaggedPush
@@ -27,7 +28,6 @@
 import Config
 import Git
 import qualified Git.Branch
-import Config.Files
 import qualified Types.Remote as Remote
 import qualified Remote as Remote
 import Remote.List
@@ -173,7 +173,7 @@
 	installwrapper tmpdir = liftIO $ do
 		createDirectoryIfMissing True tmpdir
 		let wrapper = tmpdir </> "git-remote-xmpp"
-		program <- readProgramFile
+		program <- programPath
 		writeFile wrapper $ unlines
 			[ shebang_local
 			, "exec " ++ program ++ " xmppgit"
diff --git a/Build/DistributionUpdate.hs b/Build/DistributionUpdate.hs
--- a/Build/DistributionUpdate.hs
+++ b/Build/DistributionUpdate.hs
@@ -19,7 +19,6 @@
 import Backend
 import Git.Command
 
-import Data.Default
 import Data.Time.Clock
 import Data.Char
 import System.Posix.Directory
diff --git a/Build/EvilSplicer.hs b/Build/EvilSplicer.hs
--- a/Build/EvilSplicer.hs
+++ b/Build/EvilSplicer.hs
@@ -301,8 +301,11 @@
 {- Tweaks code output by GHC in splices to actually build. Yipes. -}
 mangleCode :: String -> String
 mangleCode = flip_colon
+	. persist_dequalify_hack
+	. let_do
 	. remove_unnecessary_type_signatures
-	. lambdaparenhack
+	. lambdaparenhackyesod
+	. lambdaparenhackpersistent
 	. lambdaparens
 	. declaration_parens
 	. case_layout
@@ -383,7 +386,7 @@
 	 - FIXME: This is a hack. lambdaparens could just always add a
 	 - layer of parens even when a lambda seems to be in parent.
 	 -}
-	lambdaparenhack = parsecAndReplace $ do
+	lambdaparenhackyesod = parsecAndReplace $ do
 		indent1 <- many1 $ char ' '
 		staticr <- string "StaticR"
 		void newline
@@ -407,6 +410,44 @@
 			, indent1 ++ lambdaarrow ++ l2 ++ l3 ++ ")"
 			]
 
+	{- Hack to reorder misplaced paren in persistent code.
+	 -
+	 - = ((Right Fscked)
+         -    (\ persistValue_a36iM
+         -       -> case fromPersistValue persistValue_a36iM of {
+         -            Right r_a36iN -> Right r_a36iN
+         -            Left err_a36iO
+         -              -> (Left
+         -                  $ ((("field " `Data.Monoid.mappend` (packPTH "key"))
+         -                      `Data.Monoid.mappend` ": ")
+         -                     `Data.Monoid.mappend` err_a36iO)) }
+         -       x_a36iL))
+	 -
+	 - Fixed by adding another level of params around the lambda
+	 - (lambdaparams should be generalized to cover this case).
+	 -}
+	lambdaparenhackpersistent = parsecAndReplace $ do
+		indent1 <- many1 $ char ' '
+		start <- do
+			s1 <- string "(\\ "
+			s2 <- string "persistValue_"
+			s3 <- restofline
+			return $ s1 ++ s2 ++ s3
+		void $ string indent1
+		indent2 <- many1 $ char ' '
+		void $ string "-> "
+		l1 <- restofline
+		lambdalines <- many $ try $ do
+			void $ string $ indent1 ++ indent2 ++ " "
+			l <- restofline
+			return $ indent1 ++ indent2 ++ " " ++ l
+		return $ concat
+			[ indent1 ++ "(" ++ start ++ "\n"
+			, indent1 ++ indent2 ++ "-> " ++ l1 ++ "\n"
+			, intercalate "\n" lambdalines
+			, ")\n"
+			]
+
 	restofline = manyTill (noneOf "\n") newline
 
 	{- For some reason, GHC sometimes doesn't like the multiline
@@ -450,7 +491,7 @@
 		void newline
 		indent1 <- many1 $ char ' '
 		prefix <- manyTill (noneOf "\n") (try (string "-> "))
-		if length prefix > 10
+		if length prefix > 20
 			then unexpected "too long a prefix"
 			else if "\\ " `isInfixOf` prefix
 				then unexpected "lambda expression"
@@ -495,10 +536,13 @@
 	 -        ^^^^^^^^
 	 - The marked word should not be there.
 	 -
-	 - FIXME: This is a yesod-specific hack, it should look for the
-	 - outer instance.
+	 - FIXME: This is a yesod and persistent-specific hack,
+	 - it should look for the outer instance.
 	 -}
-	nested_instances = replace "  data instance Route" "  data Route" 
+	nested_instances = replace "  data instance Route" "  data Route"
+		. replace "  data instance Unique" "  data Unique"
+		. replace "  data instance EntityField" "  data EntityField"
+		. replace "  type instance PersistEntityBackend" "  type PersistEntityBackend"
 
 	{- GHC does not properly parenthesise generated data type
 	 - declarations. -}
@@ -553,6 +597,28 @@
 	 - that above, so have to fix up after it here. 
 	 - The ; is added by case_layout. -}
 	flip_colon = replace "; : _ " "; _ : "
+
+	{- TH for persistent has some qualified symbols in places
+	 - that are not allowed. -}
+	persist_dequalify_hack = replace "Database.Persist.TH.++" "`Data.Text.append`"
+		. replace "Database.Persist.Sql.Class.sqlType" "sqlType"
+		. replace "Database.Persist.Class.PersistField.toPersistValue" "toPersistValue"
+		. replace "Database.Persist.Class.PersistField.fromPersistValue" "fromPersistValue"
+
+	{- Sometimes generates invalid bracketed code with a let
+	 - expression:
+	 -
+	 - foo = do { let x = foo;
+	 -            use foo }
+	 -
+	 - Fix by converting the "let x = " to "x <- return $"
+	 -}
+	let_do = parsecAndReplace $ do
+		void $ string "= do { let "
+		x <- many $ noneOf "=\r\n"
+		ws <- many1 $ oneOf " \t\r\n"
+		void $ string "= "
+		return $ "= do { " ++ x ++ " <- return $ "
 
 {- Embedded files use unsafe packing, which is problimatic
  - for several reasons, including that GHC sometimes omits trailing
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,48 @@
+git-annex (5.20150317) unstable; urgency=medium
+
+  * fsck: Incremental fsck uses sqlite to store its records, instead
+    of abusing the sticky bit. Existing sticky bits are ignored;
+    incremental fscks started by old versions won't be resumed by
+    this version.
+  * fsck: Multiple incremental fscks of different repos (including remotes)
+    can now be running at the same time in the same repo without it
+    getting confused about which files have been checked for which remotes.
+  * unannex: Refuse to unannex when repo is too new to have a HEAD,
+    since in this case there must be staged changes in the index
+    (if there is anything to unannex), and the unannex code path
+    needs to run with a clean index.
+  * Linux standalone: Set LOCPATH=/dev/null to work around
+    https://ghc.haskell.org/trac/ghc/ticket/7695
+    This prevents localization from working, but git-annex
+    is not localized anyway.
+  * sync: As well as the synced/git-annex push, attempt a
+    git-annex:git-annex push, as long as the remote branch
+    is an ancestor of the local branch, to better support bare git repos.
+    (This used to be done, but it forgot to do it since version 4.20130909.)
+  * When re-execing git-annex, use current program location, rather than
+    ~/.config/git-annex/program, when possible.
+  * Submodules are now supported by git-annex!
+  * metadata: Fix encoding problem that led to mojibake when storing
+    metadata strings that contained both unicode characters and a space
+    (or '!') character.
+  * Also potentially fixes encoding problem when embedding credentials
+    that contain unicode characters.
+  * sync: Fix committing when in a direct mode repo that has no HEAD ref.
+    (For example, a newly checked out git submodule.)
+  * Added SETURIPRESENT and SETURIMISSING to external special remote protocol,
+    useful for things like ipfs that don't use regular urls.
+  * addurl: Added --raw option, which bypasses special handling of quvi,
+    bittorrent etc urls.
+  * git-annex-shell: Improve error message when the specified repository
+    doesn't exist or git config fails for some reason.
+  * fromkey --force: Skip test that the key has its content in the annex.
+  * fromkey: Add stdin mode.
+  * registerurl: New plumbing command for mass-adding urls to keys.
+  * remotedaemon: Fixed support for notifications of changes to gcrypt
+    remotes, which was never tested and didn't quite work before.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 17 Mar 2015 13:02:36 -0400
+
 git-annex (5.20150219) unstable; urgency=medium
 
   * glacier: Detect when the glacier command in PATH is the wrong one,
diff --git a/CmdLine/GitAnnex.hs b/CmdLine/GitAnnex.hs
--- a/CmdLine/GitAnnex.hs
+++ b/CmdLine/GitAnnex.hs
@@ -24,6 +24,7 @@
 import qualified Command.LookupKey
 import qualified Command.ExamineKey
 import qualified Command.FromKey
+import qualified Command.RegisterUrl
 import qualified Command.DropKey
 import qualified Command.TransferKey
 import qualified Command.TransferKeys
@@ -150,6 +151,7 @@
 	, Command.LookupKey.cmd
 	, Command.ExamineKey.cmd
 	, Command.FromKey.cmd
+	, Command.RegisterUrl.cmd
 	, Command.DropKey.cmd
 	, Command.TransferKey.cmd
 	, Command.TransferKeys.cmd
diff --git a/CmdLine/GitAnnexShell.hs b/CmdLine/GitAnnexShell.hs
--- a/CmdLine/GitAnnexShell.hs
+++ b/CmdLine/GitAnnexShell.hs
@@ -12,6 +12,7 @@
 
 import Common.Annex
 import qualified Git.Construct
+import qualified Git.Config
 import CmdLine
 import Command
 import Annex.UUID
@@ -101,11 +102,16 @@
 	let (params', fieldparams, opts) = partitionParams params
 	    fields = filter checkField $ parseFields fieldparams
 	    cmds' = map (newcmd $ unwords opts) cmds
-	dispatch False (cmd : params') cmds' options fields header $
-		Git.Construct.repoAbsPath dir >>= Git.Construct.fromAbsPath
+	dispatch False (cmd : params') cmds' options fields header mkrepo
   where
 	addrsyncopts opts seek k = setField "RsyncOptions" opts >> seek k
 	newcmd opts c = c { cmdseek = addrsyncopts opts (cmdseek c) }
+	mkrepo = do
+		r <- Git.Construct.repoAbsPath dir >>= Git.Construct.fromAbsPath
+		Git.Config.read r
+			`catchIO` \_ -> do
+				hn <- fromMaybe "unknown" <$> getHostname
+				error $ "failed to read git config of git repository in " ++ hn ++ " on " ++ dir ++ "; perhaps this repository is not set up correctly or has moved"
 
 external :: [String] -> IO ()
 external params = do
diff --git a/Command/AddUrl.hs b/Command/AddUrl.hs
--- a/Command/AddUrl.hs
+++ b/Command/AddUrl.hs
@@ -38,7 +38,7 @@
 #endif
 
 cmd :: [Command]
-cmd = [notBareRepo $ withOptions [fileOption, pathdepthOption, relaxedOption] $
+cmd = [notBareRepo $ withOptions [fileOption, pathdepthOption, relaxedOption, rawOption] $
 	command "addurl" (paramRepeating paramUrl) seek
 		SectionCommon "add urls to annex"]
 
@@ -51,14 +51,18 @@
 relaxedOption :: Option
 relaxedOption = flagOption [] "relaxed" "skip size check"
 
+rawOption :: Option
+rawOption = flagOption [] "raw" "disable special handling for torrents, quvi, etc"
+
 seek :: CommandSeek
 seek us = do
 	optfile <- getOptionField fileOption return
 	relaxed <- getOptionFlag relaxedOption
+	raw <- getOptionFlag rawOption
 	pathdepth <- getOptionField pathdepthOption (return . maybe Nothing readish)
 	forM_ us $ \u -> do
 		r <- Remote.claimingUrl u
-		if Remote.uuid r == webUUID
+		if Remote.uuid r == webUUID || raw
 			then void $ commandAction $ startWeb relaxed optfile pathdepth u
 			else do
 				pathmax <- liftIO $ fileNameLengthLimit "."
diff --git a/Command/Assistant.hs b/Command/Assistant.hs
--- a/Command/Assistant.hs
+++ b/Command/Assistant.hs
@@ -11,6 +11,7 @@
 import Command
 import qualified Command.Watch
 import Annex.Init
+import Annex.Path
 import Config.Files
 import qualified Build.SysConfig
 import Utility.HumanTime
@@ -69,7 +70,7 @@
 	when (null dirs) $ do
 		f <- autoStartFile
 		error $ "Nothing listed in " ++ f
-	program <- readProgramFile
+	program <- programPath
 	haveionice <- pure Build.SysConfig.ionice <&&> inPath "ionice"
 	forM_ dirs $ \d -> do
 		putStrLn $ "git-annex autostart in " ++ d
diff --git a/Command/FromKey.hs b/Command/FromKey.hs
--- a/Command/FromKey.hs
+++ b/Command/FromKey.hs
@@ -5,6 +5,8 @@
  - Licensed under the GNU GPL version 3 or higher.
  -}
 
+{-# LANGUAGE BangPatterns #-}
+
 module Command.FromKey where
 
 import Common.Annex
@@ -12,6 +14,7 @@
 import qualified Annex.Queue
 import Annex.Content
 import Types.Key
+import qualified Annex
 
 cmd :: [Command]
 cmd = [notDirect $ notBareRepo $
@@ -19,26 +22,44 @@
 		SectionPlumbing "adds a file using a specific key"]
 
 seek :: CommandSeek
-seek = withWords start
+seek ps = do
+	force <- Annex.getState Annex.force
+	withWords (start force) ps
 
-start :: [String] -> CommandStart
-start (keyname:file:[]) = do
+start :: Bool -> [String] -> CommandStart
+start force (keyname:file:[]) = do
 	let key = fromMaybe (error "bad key") $ file2key keyname
-	inbackend <- inAnnex key
-	unless inbackend $ error $
-		"key ("++ keyname ++") is not present in backend"
+	unless force $ do
+		inbackend <- inAnnex key
+		unless inbackend $ error $
+			"key ("++ keyname ++") is not present in backend (use --force to override this sanity check)"
 	showStart "fromkey" file
 	next $ perform key file
-start _ = error "specify a key and a dest file"
+start _ [] = do
+	showStart "fromkey" "stdin"
+	next massAdd
+start _ _ = error "specify a key and a dest file"
 
+massAdd :: CommandPerform
+massAdd = go True =<< map words . lines <$> liftIO getContents
+  where
+	go status [] = next $ return status
+	go status ([keyname,f]:rest) = do
+		let key = fromMaybe (error $ "bad key " ++ keyname) $ file2key keyname
+		ok <- perform' key f
+		let !status' = status && ok
+		go status' rest
+	go _ _ = error "Expected pairs of key and file on stdin, but got something else."
+
 perform :: Key -> FilePath -> CommandPerform
 perform key file = do
+	ok <- perform' key file
+	next $ return ok
+
+perform' :: Key -> FilePath -> Annex Bool
+perform' key file = do
 	link <- calcRepo $ gitAnnexLink file key
 	liftIO $ createDirectoryIfMissing True (parentDir file)
 	liftIO $ createSymbolicLink link file
-	next $ cleanup file
-
-cleanup :: FilePath -> CommandCleanup
-cleanup file = do
 	Annex.Queue.addCommand "add" [Param "--"] [file]
 	return True
diff --git a/Command/Fsck.hs b/Command/Fsck.hs
--- a/Command/Fsck.hs
+++ b/Command/Fsck.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2010-2013 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2015 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU GPL version 3 or higher.
  -}
@@ -26,13 +26,13 @@
 import Config.NumCopies
 import Annex.UUID
 import Utility.DataUnits
-import Utility.FileMode
 import Config
 import Types.Key
 import Types.CleanupActions
 import Utility.HumanTime
 import Git.FilePath
 import Utility.PID
+import qualified Database.Fsck as FsckDb
 
 import Data.Time.Clock.POSIX
 import Data.Time
@@ -67,14 +67,16 @@
 seek :: CommandSeek
 seek ps = do
 	from <- getOptionField fsckFromOption Remote.byNameWithUUID
-	i <- getIncremental
+	u <- maybe getUUID (pure . Remote.uuid) from
+	i <- getIncremental u
 	withKeyOptions
 		(\k -> startKey i k =<< getNumCopies)
 		(withFilesInGit $ whenAnnexed $ start from i)
 		ps
+	withFsckDb i FsckDb.closeDb
 
-getIncremental :: Annex Incremental
-getIncremental = do
+getIncremental :: UUID -> Annex Incremental
+getIncremental u = do
 	i <- maybe (return False) (checkschedule . parseDuration)
 		=<< Annex.getField (optionName incrementalScheduleOption)
 	starti <- Annex.getFlag (optionName startIncrementalOption)
@@ -82,26 +84,30 @@
 	case (i, starti, morei) of
 		(False, False, False) -> return NonIncremental
 		(False, True, False) -> startIncremental
-		(False ,False, True) -> ContIncremental <$> getStartTime
+		(False ,False, True) -> contIncremental
 		(True, False, False) ->
-			maybe startIncremental (return . ContIncremental . Just)
-				=<< getStartTime
+			maybe startIncremental (const contIncremental)
+				=<< getStartTime u
 		_ -> error "Specify only one of --incremental, --more, or --incremental-schedule"
   where
 	startIncremental = do
-		recordStartTime
-		return StartIncremental
+		recordStartTime u
+		ifM (FsckDb.newPass u)
+			( StartIncremental <$> FsckDb.openDb u
+			, error "Cannot start a new --incremental fsck pass; another fsck process is already running."
+			)
+	contIncremental = ContIncremental <$> FsckDb.openDb u
 
 	checkschedule Nothing = error "bad --incremental-schedule value"
 	checkschedule (Just delta) = do
 		Annex.addCleanup FsckCleanup $ do
-			v <- getStartTime
+			v <- getStartTime u
 			case v of
 				Nothing -> noop
 				Just started -> do
 					now <- liftIO getPOSIXTime
-					when (now - realToFrac started >= durationToPOSIXTime delta)
-						resetStartTime
+					when (now - realToFrac started >= durationToPOSIXTime delta) $
+						resetStartTime u
 		return True
 
 start :: Maybe Remote -> Incremental -> FilePath -> Key -> CommandStart
@@ -415,8 +421,7 @@
 	return $ (if ok then "dropped from " else "failed to drop from ")
 		++ Remote.name remote
 
-data Incremental = StartIncremental | ContIncremental (Maybe EpochTime) | NonIncremental
-	deriving (Eq, Show)
+data Incremental = StartIncremental FsckDb.FsckHandle | ContIncremental FsckDb.FsckHandle | NonIncremental
 
 runFsck :: Incremental -> FilePath -> Key -> Annex Bool -> CommandStart
 runFsck inc file key a = ifM (needFsck inc key)
@@ -425,48 +430,23 @@
 		next $ do
 			ok <- a
 			when ok $
-				recordFsckTime key
+				recordFsckTime inc key
 			next $ return ok
 	, stop
 	)
 
 {- Check if a key needs to be fscked, with support for incremental fscks. -}
 needFsck :: Incremental -> Key -> Annex Bool
-needFsck (ContIncremental Nothing) _ = return True
-needFsck (ContIncremental starttime) key = do
-	fscktime <- getFsckTime key
-	return $ fscktime < starttime
+needFsck (ContIncremental h) key = liftIO $ not <$> FsckDb.inDb h key
 needFsck _ _ = return True
 
-{- To record the time that a key was last fscked, without
- - modifying its mtime, we set the timestamp of its parent directory.
- - Each annexed file is the only thing in its directory, so this is fine.
- -
- - To record that the file was fscked, the directory's sticky bit is set.
- - (None of the normal unix behaviors of the sticky bit should matter, so
- - we can reuse this permission bit.)
- -
- - Note that this relies on the parent directory being deleted when a file
- - is dropped. That way, if it's later added back, the fsck record
- - won't still be present.
- -}
-recordFsckTime :: Key -> Annex ()
-recordFsckTime key = do
-	parent <- parentDir <$> calcRepo (gitAnnexLocation key)
-	liftIO $ void $ tryIO $ do
-		touchFile parent
-#ifndef mingw32_HOST_OS
-		setSticky parent
-#endif
+withFsckDb :: Incremental -> (FsckDb.FsckHandle -> Annex ()) -> Annex ()
+withFsckDb (ContIncremental h) a = a h
+withFsckDb (StartIncremental h) a = a h
+withFsckDb NonIncremental _ = noop
 
-getFsckTime :: Key -> Annex (Maybe EpochTime)
-getFsckTime key = do
-	parent <- parentDir <$> calcRepo (gitAnnexLocation key)
-	liftIO $ catchDefaultIO Nothing $ do
-		s <- getFileStatus parent
-		return $ if isSticky $ fileMode s
-			then Just $ modificationTime s
-			else Nothing
+recordFsckTime :: Incremental -> Key -> Annex ()
+recordFsckTime inc key = withFsckDb inc $ \h -> liftIO $ FsckDb.addDb h key
 
 {- Records the start time of an incremental fsck.
  -
@@ -476,9 +456,9 @@
  - (This is not possible to do on Windows, and so the timestamp in
  - the file will only be equal or greater than the modification time.)
  -}
-recordStartTime :: Annex ()
-recordStartTime = do
-	f <- fromRepo gitAnnexFsckState
+recordStartTime :: UUID -> Annex ()
+recordStartTime u = do
+	f <- fromRepo (gitAnnexFsckState u)
 	createAnnexDirectory $ parentDir f
 	liftIO $ do
 		nukeFile f
@@ -493,13 +473,13 @@
 	showTime :: POSIXTime -> String
 	showTime = show
 
-resetStartTime :: Annex ()
-resetStartTime = liftIO . nukeFile =<< fromRepo gitAnnexFsckState
+resetStartTime :: UUID -> Annex ()
+resetStartTime u = liftIO . nukeFile =<< fromRepo (gitAnnexFsckState u)
 
 {- Gets the incremental fsck start time. -}
-getStartTime :: Annex (Maybe EpochTime)
-getStartTime = do
-	f <- fromRepo gitAnnexFsckState
+getStartTime :: UUID -> Annex (Maybe EpochTime)
+getStartTime u = do
+	f <- fromRepo (gitAnnexFsckState u)
 	liftIO $ catchDefaultIO Nothing $ do
 		timestamp <- modificationTime <$> getFileStatus f
 		let fromstatus = Just (realToFrac timestamp)
diff --git a/Command/ImportFeed.hs b/Command/ImportFeed.hs
--- a/Command/ImportFeed.hs
+++ b/Command/ImportFeed.hs
@@ -28,7 +28,7 @@
 import Logs.Web
 import qualified Utility.Format
 import Utility.Tmp
-import Command.AddUrl (addUrlFile, downloadRemoteFile, relaxedOption)
+import Command.AddUrl (addUrlFile, downloadRemoteFile, relaxedOption, rawOption)
 import Annex.Perms
 import Annex.UUID
 import Backend.URL (fromUrl)
@@ -42,7 +42,7 @@
 import Annex.MetaData
 
 cmd :: [Command]
-cmd = [notBareRepo $ withOptions [templateOption, relaxedOption] $
+cmd = [notBareRepo $ withOptions [templateOption, relaxedOption, rawOption] $
 	command "importfeed" (paramRepeating paramUrl) seek
 		SectionCommon "import files from podcast feeds"]
 
@@ -53,23 +53,30 @@
 seek ps = do
 	tmpl <- getOptionField templateOption return
 	relaxed <- getOptionFlag relaxedOption
+	raw <- getOptionFlag rawOption
+	let opts = Opts { relaxedOpt = relaxed, rawOpt = raw }
 	cache <- getCache tmpl
-	withStrings (start relaxed cache) ps
+	withStrings (start opts cache) ps
 
-start :: Bool -> Cache -> URLString -> CommandStart
-start relaxed cache url = do
+data Opts = Opts
+	{ relaxedOpt :: Bool
+	, rawOpt :: Bool
+	}
+
+start :: Opts -> Cache -> URLString -> CommandStart
+start opts cache url = do
 	showStart "importfeed" url
-	next $ perform relaxed cache url
+	next $ perform opts cache url
 
-perform :: Bool -> Cache -> URLString -> CommandPerform
-perform relaxed cache url = do
+perform :: Opts -> Cache -> URLString -> CommandPerform
+perform opts cache url = do
 	v <- findDownloads url
 	case v of
 		[] -> do
 			feedProblem url "bad feed content"
 			next $ return True
 		l -> do
-			ok <- and <$> mapM (performDownload relaxed cache) l
+			ok <- and <$> mapM (performDownload opts cache) l
 			unless ok $
 				feedProblem url "problem downloading item"
 			next $ cleanup url True
@@ -138,15 +145,15 @@
 			, return Nothing
 			)
 
-performDownload :: Bool -> Cache -> ToDownload -> Annex Bool
-performDownload relaxed cache todownload = case location todownload of
+performDownload :: Opts -> Cache -> ToDownload -> Annex Bool
+performDownload opts cache todownload = case location todownload of
 	Enclosure url -> checkknown url $
 		rundownload url (takeExtension url) $ \f -> do
 			r <- Remote.claimingUrl url
-			if Remote.uuid r == webUUID
+			if Remote.uuid r == webUUID || rawOpt opts
 				then do
 					urlinfo <- Url.withUrlOptions (Url.getUrlInfo url)
-					maybeToList <$> addUrlFile relaxed url urlinfo f
+					maybeToList <$> addUrlFile (relaxedOpt opts) url urlinfo f
 				else do
 					res <- tryNonAsync $ maybe
 						(error $ "unable to checkUrl of " ++ Remote.name r)
@@ -156,10 +163,10 @@
 						Left _ -> return []
 						Right (UrlContents sz _) ->
 							maybeToList <$>
-								downloadRemoteFile r relaxed url f sz
+								downloadRemoteFile r (relaxedOpt opts) url f sz
 						Right (UrlMulti l) -> do
 							kl <- forM l $ \(url', sz, subf) ->
-								downloadRemoteFile r relaxed url' (f </> fromSafeFilePath subf) sz
+								downloadRemoteFile r (relaxedOpt opts) url' (f </> fromSafeFilePath subf) sz
 							return $ if all isJust kl
 								then catMaybes kl
 								else []
@@ -177,7 +184,7 @@
 						let videourl = Quvi.linkUrl link
 						checkknown videourl $
 							rundownload videourl ("." ++ Quvi.linkSuffix link) $ \f ->
-								maybeToList <$> addUrlFileQuvi relaxed quviurl videourl f
+								maybeToList <$> addUrlFileQuvi (relaxedOpt opts) quviurl videourl f
 #else
 		return False
 #endif
diff --git a/Command/Proxy.hs b/Command/Proxy.hs
--- a/Command/Proxy.hs
+++ b/Command/Proxy.hs
@@ -13,8 +13,8 @@
 import Utility.Tmp
 import Utility.Env
 import Annex.Direct
-import qualified Git.Branch
 import qualified Git.Sha
+import qualified Git.Ref
 
 cmd :: [Command]
 cmd = [notBareRepo $
@@ -35,7 +35,7 @@
   where
 	go tmp = do
 		oldref <- fromMaybe Git.Sha.emptyTree
-			<$> inRepo Git.Branch.currentSha
+			<$> inRepo Git.Ref.headSha
 		exitcode <- liftIO $ proxy tmp
 		mergeDirectCleanup tmp oldref
 		return exitcode
diff --git a/Command/RegisterUrl.hs b/Command/RegisterUrl.hs
new file mode 100644
--- /dev/null
+++ b/Command/RegisterUrl.hs
@@ -0,0 +1,55 @@
+{- git-annex command
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+{-# LANGUAGE BangPatterns #-}
+
+module Command.RegisterUrl where
+
+import Common.Annex
+import Command
+import Types.Key
+import Logs.Web
+import Annex.UUID
+
+cmd :: [Command]
+cmd = [notDirect $ notBareRepo $
+	command "registerurl" (paramPair paramKey paramUrl) seek
+		SectionPlumbing "registers an url for a key"]
+
+seek :: CommandSeek
+seek = withWords start
+
+start :: [String] -> CommandStart
+start (keyname:url:[]) = do
+	let key = fromMaybe (error "bad key") $ file2key keyname
+	showStart "registerurl" url
+	next $ perform key url
+start [] = do
+	showStart "registerurl" "stdin"
+	next massAdd
+start _ = error "specify a key and an url"
+
+massAdd :: CommandPerform
+massAdd = go True =<< map words . lines <$> liftIO getContents
+  where
+	go status [] = next $ return status
+	go status ([keyname,u]:rest) = do
+		let key = fromMaybe (error $ "bad key " ++ keyname) $ file2key keyname
+		ok <- perform' key u
+		let !status' = status && ok
+		go status' rest
+	go _ _ = error "Expected pairs of key and url on stdin, but got something else."
+
+perform :: Key -> URLString -> CommandPerform
+perform key url = do
+	ok <- perform' key url
+	next $ return ok
+
+perform' :: Key -> URLString -> Annex Bool
+perform' key url = do
+	setUrlPresent webUUID key url
+	return True
diff --git a/Command/Sync.hs b/Command/Sync.hs
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -71,8 +71,9 @@
 	prepMerge
 
 	-- There may not be a branch checked out until after the commit,
-	-- or perhaps after it gets merged from the remote.
-	-- So only look it up once it's needed, and if once there is a
+	-- or perhaps after it gets merged from the remote, or perhaps
+	-- never.
+	-- So only look it up once it's needed, and once there is a
 	-- branch, cache it.
 	mvar <- liftIO newEmptyMVar
 	let getbranch = ifM (liftIO $ isEmptyMVar mvar)
@@ -173,15 +174,15 @@
 	return $ "git-annex in " ++ fromMaybe "unknown" (M.lookup u m)
 
 commitStaged :: Git.Branch.CommitMode -> String -> Annex Bool
-commitStaged commitmode commitmessage = go =<< inRepo Git.Branch.currentUnsafe
-  where
-	go Nothing = return False
-	go (Just branch) = do
-		runAnnexHook preCommitAnnexHook
-		parent <- inRepo $ Git.Ref.sha branch
-		void $ inRepo $ Git.Branch.commit commitmode False commitmessage branch
-			(maybeToList parent)
-		return True
+commitStaged commitmode commitmessage = do
+	runAnnexHook preCommitAnnexHook
+	mb <- inRepo Git.Branch.currentUnsafe
+	let (getparent, branch) = case mb of
+		Just b -> (Git.Ref.sha b, b)
+		Nothing -> (Git.Ref.headSha, Git.Ref.headRef)
+	parents <- maybeToList <$> inRepo getparent
+	void $ inRepo $ Git.Branch.commit commitmode False commitmessage branch parents
+	return True
 
 mergeLocal :: Maybe Git.Ref -> CommandStart
 mergeLocal Nothing = stop
@@ -315,7 +316,9 @@
 		, refspec branch
 		]
 	directpush = Git.Command.runQuiet $ pushparams
-		[Git.fromRef $ Git.Ref.base $ fromDirectBranch branch]
+		[ Git.fromRef $ Git.Ref.base $ Annex.Branch.name
+		, Git.fromRef $ Git.Ref.base $ fromDirectBranch branch
+		]
 	pushparams branches =
 		[ Param "push"
 		, Param $ Remote.name remote
diff --git a/Command/Unannex.hs b/Command/Unannex.hs
--- a/Command/Unannex.hs
+++ b/Command/Unannex.hs
@@ -53,11 +53,14 @@
 		, Param "--no-verify"
 		, Param "-m", Param "content removed from git annex"
 		]
-	cleanindex = do
-		(diff, cleanup) <- inRepo $ DiffTree.diffIndex Git.Ref.headRef
-		if null diff
-			then void (liftIO cleanup) >> return True
-			else void (liftIO cleanup) >> return False
+	cleanindex = ifM (inRepo Git.Ref.headExists)
+		( do
+			(diff, cleanup) <- inRepo $ DiffTree.diffIndex Git.Ref.headRef
+			if null diff
+				then void (liftIO cleanup) >> return True
+				else void (liftIO cleanup) >> return False
+		, return False
+		)
 
 start :: FilePath -> Key -> CommandStart
 start file key = stopUnless (inAnnex key) $ do
diff --git a/Config.hs b/Config.hs
--- a/Config.hs
+++ b/Config.hs
@@ -37,13 +37,9 @@
 reloadConfig :: Annex ()
 reloadConfig = Annex.changeGitRepo =<< inRepo Git.Config.reRead
 
-{- Unsets a git config setting. (Leaves it in state currently.) -}
+{- Unsets a git config setting. (Leaves it in state.) -}
 unsetConfig :: ConfigKey -> Annex ()
-unsetConfig ck@(ConfigKey key) = ifM (isJust <$> getConfigMaybe ck)
-	( inRepo $ Git.Command.run
-		[Param "config", Param "--unset", Param key]
-	, noop -- avoid unsetting something not set; that would fail
-	)
+unsetConfig (ConfigKey key) = void $ inRepo $ Git.Config.unset key
 
 {- A per-remote config setting in git config. -}
 remoteConfig :: Git.Repo -> UnqualifiedConfigKey -> ConfigKey
diff --git a/Config/Files.hs b/Config/Files.hs
--- a/Config/Files.hs
+++ b/Config/Files.hs
@@ -62,8 +62,13 @@
 		( return p
 		, ifM (inPath cmd)
 			( return cmd
-			, error $ "cannot find git-annex program in PATH or in the location listed in " ++ programfile
+			, cannotFindProgram
 			)
 		)
   where
 	cmd = "git-annex"
+
+cannotFindProgram :: IO a
+cannotFindProgram = do
+	f <- programFile
+	error $ "cannot find git-annex program in PATH or in the location listed in " ++ f
diff --git a/Database/Fsck.hs b/Database/Fsck.hs
new file mode 100644
--- /dev/null
+++ b/Database/Fsck.hs
@@ -0,0 +1,106 @@
+{- Sqlite database used for incremental fsck. 
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -:
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+{-# LANGUAGE QuasiQuotes, TypeFamilies, TemplateHaskell #-}
+{-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE RankNTypes #-}
+
+module Database.Fsck (
+	FsckHandle,
+	newPass,
+	openDb,
+	closeDb,
+	addDb,
+	inDb,
+	FsckedId,
+) where
+
+import Database.Types
+import qualified Database.Handle as H
+import Locations
+import Utility.PosixFiles
+import Utility.Exception
+import Annex
+import Types.Key
+import Types.UUID
+import Annex.Perms
+import Annex.LockFile
+
+import Database.Persist.TH
+import Database.Esqueleto hiding (Key)
+import Control.Monad
+import Control.Monad.IfElse
+import Control.Monad.IO.Class (liftIO)
+import System.Directory
+import System.FilePath
+import Data.Maybe
+import Control.Applicative
+
+data FsckHandle = FsckHandle H.DbHandle UUID
+
+{- Each key stored in the database has already been fscked as part
+ - of the latest incremental fsck pass. -}
+share [mkPersist sqlSettings, mkMigrate "migrateFsck"] [persistLowerCase|
+Fscked
+  key SKey
+  UniqueKey key
+|]
+
+{- The database is removed when starting a new incremental fsck pass.
+ -
+ - This may fail, if other fsck processes are currently running using the
+ - database. Removing the database in that situation would lead to crashes
+ - or undefined behavior.
+ -}
+newPass :: UUID -> Annex Bool
+newPass u = isJust <$> tryExclusiveLock (gitAnnexFsckDbLock u) go
+  where
+	go = liftIO . void . tryIO . removeDirectoryRecursive
+		=<< fromRepo (gitAnnexFsckDbDir u)
+
+{- Opens the database, creating it atomically if it doesn't exist yet. -}
+openDb :: UUID -> Annex FsckHandle
+openDb u = do
+	dbdir <- fromRepo (gitAnnexFsckDbDir u)
+	let db = dbdir </> "db"
+	unlessM (liftIO $ doesFileExist db) $ do
+		let tmpdbdir = dbdir ++ ".tmp"
+		let tmpdb = tmpdbdir </> "db"
+		liftIO $ do
+			createDirectoryIfMissing True tmpdbdir
+			H.initDb tmpdb $ void $
+				runMigrationSilent migrateFsck
+		setAnnexDirPerm tmpdbdir
+		setAnnexFilePerm tmpdb
+		liftIO $ do
+			void $ tryIO $ removeDirectoryRecursive dbdir
+			rename tmpdbdir dbdir
+	lockFileShared =<< fromRepo (gitAnnexFsckDbLock u)
+	h <- liftIO $ H.openDb db "fscked"
+	return $ FsckHandle h u
+
+closeDb :: FsckHandle -> Annex ()
+closeDb (FsckHandle h u) = do
+	liftIO $ H.closeDb h
+	unlockFile =<< fromRepo (gitAnnexFsckDbLock u)
+
+addDb :: FsckHandle -> Key -> IO ()
+addDb (FsckHandle h _) k = H.queueDb h 1000 $ 
+	void $ insertUnique $ Fscked sk
+  where
+	sk = toSKey k
+
+inDb :: FsckHandle -> Key -> IO Bool
+inDb (FsckHandle h _) = H.queryDb h . inDb' . toSKey
+
+inDb' :: SKey -> SqlPersistM Bool
+inDb' sk = do
+	r <- select $ from $ \r -> do
+		where_ (r ^. FsckedKey ==. val sk)
+		return (r ^. FsckedKey)
+	return $ not $ null r
diff --git a/Database/Handle.hs b/Database/Handle.hs
new file mode 100644
--- /dev/null
+++ b/Database/Handle.hs
@@ -0,0 +1,204 @@
+{- Persistent sqlite database handles.
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+{-# LANGUAGE BangPatterns #-}
+
+module Database.Handle (
+	DbHandle,
+	initDb,
+	openDb,
+	queryDb,
+	closeDb,
+	Size,
+	queueDb,
+	flushQueueDb,
+	commitDb,
+) where
+
+import Utility.Exception
+import Messages
+
+import Database.Persist.Sqlite
+import qualified Database.Sqlite as Sqlite
+import Control.Monad
+import Control.Monad.IO.Class (liftIO)
+import Control.Concurrent
+import Control.Concurrent.Async
+import Control.Exception (throwIO)
+import qualified Data.Text as T
+import Control.Monad.Trans.Resource (runResourceT)
+import Control.Monad.Logger (runNoLoggingT)
+import Data.List
+
+{- A DbHandle is a reference to a worker thread that communicates with
+ - the database. It has a MVar which Jobs are submitted to. -}
+data DbHandle = DbHandle (Async ()) (MVar Job) (MVar DbQueue)
+
+{- Ensures that the database is initialized. Pass the migration action for
+ - the database.
+ -
+ - The database is put into WAL mode, to prevent readers from blocking
+ - writers, and prevent a writer from blocking readers.
+ -}
+initDb :: FilePath -> SqlPersistM () -> IO ()
+initDb f migration = do
+	let db = T.pack f
+	enableWAL db
+	runSqlite db migration
+
+enableWAL :: T.Text -> IO ()
+enableWAL db = do
+	conn <- Sqlite.open db
+	stmt <- Sqlite.prepare conn (T.pack "PRAGMA journal_mode=WAL;")
+	void $ Sqlite.step stmt
+	void $ Sqlite.finalize stmt
+	Sqlite.close conn
+
+{- Opens the database, but does not perform any migrations. Only use
+ - if the database is known to exist and have the right tables. -}
+openDb :: FilePath -> TableName -> IO DbHandle
+openDb db tablename = do
+	jobs <- newEmptyMVar
+	worker <- async (workerThread (T.pack db) tablename jobs)
+	q <- newMVar emptyDbQueue
+	return $ DbHandle worker jobs q
+
+data Job
+	= QueryJob (SqlPersistM ())
+	| ChangeJob ((SqlPersistM () -> IO ()) -> IO ())
+	| CloseJob
+
+type TableName = String
+
+workerThread :: T.Text -> TableName -> MVar Job -> IO ()
+workerThread db tablename jobs = catchNonAsync (run loop) showerr
+  where
+  	showerr e = liftIO $ warningIO $
+		"sqlite worker thread crashed: " ++ show e
+	
+	loop = do
+		job <- liftIO $ takeMVar jobs
+		case job of
+			QueryJob a -> a >> loop
+			-- change is run in a separate database connection
+			-- since sqlite only supports a single writer at a
+			-- time, and it may crash the database connection
+			ChangeJob a -> liftIO (a run) >> loop
+			CloseJob -> return ()
+	
+	-- like runSqlite, but calls settle on the raw sql Connection.
+	run a = do
+		conn <- Sqlite.open db
+		settle conn
+		runResourceT $ runNoLoggingT $
+			withSqlConn (wrapConnection conn) $
+				runSqlConn a
+
+	-- Work around a bug in sqlite: New database connections can
+	-- sometimes take a while to become usable; select statements will
+	-- fail with ErrorBusy for some time. So, loop until a select
+	-- succeeds; once one succeeds the connection will stay usable.
+	-- <http://thread.gmane.org/gmane.comp.db.sqlite.general/93116>
+	settle conn = do
+		r <- tryNonAsync $ do
+			stmt <- Sqlite.prepare conn nullselect
+			void $ Sqlite.step stmt
+			void $ Sqlite.finalize stmt
+		case r of
+			Right _ -> return ()
+			Left e -> do
+				if "ErrorBusy" `isInfixOf` show e
+					then do
+						threadDelay 1000 -- 1/1000th second
+						settle conn
+					else throwIO e
+	
+	-- This should succeed for any table.
+	nullselect = T.pack $ "SELECT null from " ++ tablename ++ " limit 1"
+
+{- Makes a query using the DbHandle. This should not be used to make
+ - changes to the database!
+ -
+ - Note that the action is not run by the calling thread, but by a
+ - worker thread. Exceptions are propigated to the calling thread.
+ -
+ - Only one action can be run at a time against a given DbHandle.
+ - If called concurrently in the same process, this will block until
+ - it is able to run.
+ -}
+queryDb :: DbHandle -> SqlPersistM a -> IO a
+queryDb (DbHandle _ jobs _) a = do
+	res <- newEmptyMVar
+	putMVar jobs $ QueryJob $
+		liftIO . putMVar res =<< tryNonAsync a
+	either throwIO return =<< takeMVar res
+
+closeDb :: DbHandle -> IO ()
+closeDb h@(DbHandle worker jobs _) = do
+	flushQueueDb h
+	putMVar jobs CloseJob
+	wait worker
+
+type Size = Int
+
+{- A queue of actions to perform, with a count of the number of actions
+ - queued. -}
+data DbQueue = DbQueue Size (SqlPersistM ())
+
+emptyDbQueue :: DbQueue
+emptyDbQueue = DbQueue 0 (return ())
+
+{- Queues a change to be made to the database. It will be buffered
+ - to be committed later, unless the queue gets larger than the specified
+ - size.
+ -
+ - (Be sure to call closeDb or flushQueueDb to ensure the change
+ - gets committed.)
+ -
+ - Transactions built up by queueDb are sent to sqlite all at once.
+ - If sqlite fails due to another change being made concurrently by another
+ - process, the transaction is put back in the queue. This solves
+ - the sqlite multiple writer problem.
+ -}
+queueDb :: DbHandle -> Size -> SqlPersistM () -> IO ()
+queueDb h@(DbHandle _ _ qvar) maxsz a = do
+	DbQueue sz qa <- takeMVar qvar
+	let !sz' = sz + 1
+	let qa' = qa >> a
+	let enqueue newsz = putMVar qvar (DbQueue newsz qa')
+	if sz' > maxsz
+		then do
+			r <- commitDb h qa'
+			case r of
+				Left _ -> enqueue 0
+				Right _ -> putMVar qvar emptyDbQueue
+		else enqueue sz'
+
+{- If flushing the queue fails, this could be because there is another
+ - writer to the database. Retry repeatedly for up to 10 seconds. -}
+flushQueueDb :: DbHandle -> IO ()
+flushQueueDb h@(DbHandle _ _ qvar) = do
+	DbQueue sz qa <- takeMVar qvar	
+	when (sz > 0) $
+		robustly Nothing 100 (commitDb h qa)
+  where
+	robustly :: Maybe SomeException -> Int -> IO (Either SomeException ()) -> IO ()
+	robustly e 0 _ = error $ "failed to commit changes to sqlite database: " ++ show e
+	robustly _ n a = do
+		r <- a
+		case r of
+			Right _ -> return ()
+			Left e -> do
+				threadDelay 100000 -- 1/10th second
+				robustly (Just e) (n-1) a
+
+commitDb :: DbHandle -> SqlPersistM () -> IO (Either SomeException ())
+commitDb (DbHandle _ jobs _) a = do
+	res <- newEmptyMVar
+	putMVar jobs $ ChangeJob $ \runner ->
+		liftIO $ putMVar res =<< tryNonAsync (runner a)
+	takeMVar res
diff --git a/Database/Types.hs b/Database/Types.hs
new file mode 100644
--- /dev/null
+++ b/Database/Types.hs
@@ -0,0 +1,27 @@
+{- types for SQL databases
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+{-# LANGUAGE TemplateHaskell #-}
+
+module Database.Types where
+
+import Database.Persist.TH
+import Data.Maybe
+
+import Types.Key
+
+-- A serialized Key
+newtype SKey = SKey String
+	deriving (Show, Read)
+
+toSKey :: Key -> SKey
+toSKey = SKey . key2file
+
+fromSKey :: SKey -> Key
+fromSKey (SKey s) = fromMaybe (error $ "bad serialied key " ++ s) (file2key s)
+
+derivePersistField "SKey"
diff --git a/Git/Branch.hs b/Git/Branch.hs
--- a/Git/Branch.hs
+++ b/Git/Branch.hs
@@ -37,14 +37,11 @@
 {- The current branch, which may not really exist yet. -}
 currentUnsafe :: Repo -> IO (Maybe Git.Ref)
 currentUnsafe r = parse . firstLine
-	<$> pipeReadStrict [Param "symbolic-ref", Param $ fromRef Git.Ref.headRef] r
+	<$> pipeReadStrict [Param "symbolic-ref", Param "-q", Param $ fromRef Git.Ref.headRef] r
   where
 	parse l
 		| null l = Nothing
 		| otherwise = Just $ Git.Ref l
-
-currentSha :: Repo -> IO (Maybe Git.Sha)
-currentSha r = maybe (pure Nothing) (`Git.Ref.sha` r) =<< current r
 
 {- Checks if the second branch has any commits not present on the first
  - branch. -}
diff --git a/Git/Config.hs b/Git/Config.hs
--- a/Git/Config.hs
+++ b/Git/Config.hs
@@ -14,6 +14,7 @@
 import Git
 import Git.Types
 import qualified Git.Construct
+import qualified Git.Command
 import Utility.UserInfo
 
 {- Returns a single git config setting, or a default value if not set. -}
@@ -193,3 +194,17 @@
 	, Param k
 	, Param v
 	]
+
+{- Unsets a git config setting, in both the git repo,
+ - and the cached config in the Repo.
+ -
+ - If unsetting the config fails, including in a read-only repo, or
+ - when the config is not set, returns Nothing.
+ -}
+unset :: String -> Repo -> IO (Maybe Repo)
+unset k r = ifM (Git.Command.runBool ps r)
+	( return $ Just $ r { config = M.delete k (config r) }
+	, return Nothing
+	)
+  where
+	ps = [Param "config", Param "--unset-all", Param k]
diff --git a/Git/Ref.hs b/Git/Ref.hs
--- a/Git/Ref.hs
+++ b/Git/Ref.hs
@@ -88,6 +88,9 @@
 	process [] = Nothing
 	process s = Just $ Ref $ firstLine s
 
+headSha :: Repo -> IO (Maybe Sha)
+headSha = sha headRef
+
 {- List of (shas, branches) matching a given ref or refs. -}
 matching :: [Ref] -> Repo -> IO [(Sha, Branch)]
 matching refs repo =  matching' (map fromRef refs) repo
diff --git a/INSTALL b/INSTALL
--- a/INSTALL
+++ b/INSTALL
@@ -9,7 +9,7 @@
 &nbsp;&nbsp;[[Debian]]            | `apt-get install git-annex`
 &nbsp;&nbsp;[[Ubuntu]]            | `apt-get install git-annex`
 &nbsp;&nbsp;[[Fedora]]            | `yum install git-annex`
-&nbsp;&nbsp;[[FreeBSD]]           | `pkg_add -r hs-git-annex`
+&nbsp;&nbsp;[[FreeBSD]]           | `pkg install hs-git-annex`
 &nbsp;&nbsp;[[ArchLinux]]         | `yaourt -Sy git-annex-bin`
 &nbsp;&nbsp;[[NixOS]]             | `nix-env -i git-annex`
 &nbsp;&nbsp;[[Gentoo]]            | `emerge git-annex`
diff --git a/Locations.hs b/Locations.hs
--- a/Locations.hs
+++ b/Locations.hs
@@ -29,6 +29,8 @@
 	gitAnnexBadLocation,
 	gitAnnexUnusedLog,
 	gitAnnexFsckState,
+	gitAnnexFsckDbDir,
+	gitAnnexFsckDbLock,
 	gitAnnexFsckResultsLog,
 	gitAnnexScheduleState,
 	gitAnnexTransferDir,
@@ -77,6 +79,7 @@
 import qualified Git
 import Git.FilePath
 import Annex.DirHashes
+import Annex.Fixup
 
 {- Conventions:
  -
@@ -124,9 +127,9 @@
  - the actual location of the file's content.
  -}
 gitAnnexLocation :: Key -> Git.Repo -> GitConfig -> IO FilePath
-gitAnnexLocation key r config = gitAnnexLocation' key r config (annexCrippledFileSystem config)
-gitAnnexLocation' :: Key -> Git.Repo -> GitConfig -> Bool -> IO FilePath
-gitAnnexLocation' key r config crippled
+gitAnnexLocation key r config = gitAnnexLocation' key r config (annexCrippledFileSystem config) doesFileExist (Git.localGitDir r)
+gitAnnexLocation' :: Key -> Git.Repo -> GitConfig -> Bool -> (FilePath -> IO Bool) -> FilePath -> IO FilePath
+gitAnnexLocation' key r config crippled checker gitdir
 	{- Bare repositories default to hashDirLower for new
 	 - content, as it's more portable.
 	 -
@@ -145,18 +148,27 @@
 	 - present. -}
 	| otherwise = return $ inrepo $ annexLocation config key hashDirMixed
   where
-	inrepo d = Git.localGitDir r </> d
-	check locs@(l:_) = fromMaybe l <$> firstM doesFileExist locs
+	inrepo d = gitdir </> d
+	check locs@(l:_) = fromMaybe l <$> firstM checker locs
 	check [] = error "internal"
 
-{- Calculates a symlink to link a file to an annexed object. -}
+{- Calculates a symlink target to link a file to an annexed object. -}
 gitAnnexLink :: FilePath -> Key -> Git.Repo -> GitConfig -> IO FilePath
 gitAnnexLink file key r config = do
 	currdir <- getCurrentDirectory
 	let absfile = fromMaybe whoops $ absNormPathUnix currdir file
-	loc <- gitAnnexLocation' key r config False
+	let gitdir = getgitdir currdir
+	loc <- gitAnnexLocation' key r config False (\_ -> return True) gitdir
 	toInternalGitPath <$> relPathDirToFile (parentDir absfile) loc
   where
+	getgitdir currdir
+		{- This special case is for git submodules on filesystems not
+		 - supporting symlinks; generate link target that will
+		 - work portably. -}
+		| coreSymlinks config == False && needsSubmoduleFixup r =
+			fromMaybe whoops $ absNormPathUnix currdir $
+				Git.repoPath r </> ".git"
+		| otherwise = Git.localGitDir r
 	whoops = error $ "unable to normalize " ++ file
 
 {- File used to lock a key's content. -}
@@ -218,9 +230,22 @@
 gitAnnexUnusedLog :: FilePath -> Git.Repo -> FilePath
 gitAnnexUnusedLog prefix r = gitAnnexDir r </> (prefix ++ "unused")
 
-{- .git/annex/fsckstate is used to store information about incremental fscks. -}
-gitAnnexFsckState :: Git.Repo -> FilePath
-gitAnnexFsckState r = gitAnnexDir r </> "fsckstate"
+{- .git/annex/fsck/uuid/ is used to store information about incremental
+ - fscks. -}
+gitAnnexFsckDir :: UUID -> Git.Repo -> FilePath
+gitAnnexFsckDir u r = gitAnnexDir r </> "fsck" </> fromUUID u
+
+{- used to store information about incremental fscks. -}
+gitAnnexFsckState :: UUID -> Git.Repo -> FilePath
+gitAnnexFsckState u r = gitAnnexFsckDir u r </> "state"
+
+{- Directory containing database used to record fsck info. -}
+gitAnnexFsckDbDir :: UUID -> Git.Repo -> FilePath
+gitAnnexFsckDbDir u r = gitAnnexFsckDir u r </> "db"
+
+{- Lock file for the fsck database. -}
+gitAnnexFsckDbLock :: UUID -> Git.Repo -> FilePath
+gitAnnexFsckDbLock u r = gitAnnexFsckDir u r </> "fsck.lck"
 
 {- .git/annex/fsckresults/uuid is used to store results of git fscks -}
 gitAnnexFsckResultsLog :: UUID -> Git.Repo -> FilePath
diff --git a/Logs/Web.hs b/Logs/Web.hs
--- a/Logs/Web.hs
+++ b/Logs/Web.hs
@@ -94,7 +94,7 @@
 	s { Annex.tempurls = M.delete key (Annex.tempurls s) }
 
 data Downloader = WebDownloader | QuviDownloader | OtherDownloader
-	deriving (Eq)
+	deriving (Eq, Show)
 
 {- To keep track of how an url is downloaded, it's mangled slightly in
  - the log. For quvi, "quvi:" is prefixed. For urls that are handled by
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -185,7 +185,7 @@
 # and not overwritten.)
 	cp -uR tmp/splices/* tmp/no-th-tree || true
 # Some additional dependencies needed by the expanded splices.
-	sed -i 's/^  Build-Depends: /  Build-Depends: yesod-routes, yesod-core, shakespeare-css, shakespeare-js, shakespeare, blaze-markup, file-embed, wai-app-static, /' tmp/no-th-tree/git-annex.cabal
+	sed -i 's/^  Build-Depends: /  Build-Depends: yesod-routes, yesod-core, shakespeare-css, shakespeare-js, shakespeare, blaze-markup, file-embed, wai-app-static, unordered-containers, /' tmp/no-th-tree/git-annex.cabal
 # Avoid warnings due to sometimes unused imports added for the splices.
 	sed -i 's/GHC-Options: \(.*\)-Wall/GHC-Options: \1-Wall -fno-warn-unused-imports /i' tmp/no-th-tree/git-annex.cabal
 	sed -i 's/Extensions: /Extensions: MagicHash /i' tmp/no-th-tree/git-annex.cabal
@@ -215,7 +215,7 @@
 # and not overwritten.)
 	cp -uR tmp/splices/* tmp/androidtree || true
 # Some additional dependencies needed by the expanded splices.
-	sed -i 's/^  Build-Depends: /  Build-Depends: yesod-routes, yesod-core, shakespeare-css, shakespeare-js, shakespeare, blaze-markup, file-embed, wai-app-static, /' tmp/androidtree/git-annex.cabal
+	sed -i 's/^  Build-Depends: /  Build-Depends: yesod-routes, yesod-core, shakespeare-css, shakespeare-js, shakespeare, blaze-markup, file-embed, wai-app-static, unordered-containers, /' tmp/androidtree/git-annex.cabal
 # Avoid warnings due to sometimes unused imports added for the splices.
 	sed -i 's/GHC-Options: \(.*\)-Wall/GHC-Options: \1-Wall -fno-warn-unused-imports /i' tmp/androidtree/git-annex.cabal
 	sed -i 's/Extensions: /Extensions: MagicHash /i' tmp/androidtree/git-annex.cabal
diff --git a/Remote/External.hs b/Remote/External.hs
--- a/Remote/External.hs
+++ b/Remote/External.hs
@@ -223,6 +223,10 @@
 		setUrlPresent (externalUUID external) key url
 	handleRemoteRequest (SETURLMISSING key url) =
 		setUrlMissing (externalUUID external) key url
+	handleRemoteRequest (SETURIPRESENT key uri) =
+		withurl (SETURLPRESENT key) uri
+	handleRemoteRequest (SETURIMISSING key uri) =
+		withurl (SETURLMISSING key) uri
 	handleRemoteRequest (GETURLS key prefix) = do
 		mapM_ (send . VALUE . fst . getDownloader)
 			=<< getUrlsWithPrefix key prefix
@@ -242,6 +246,9 @@
 		}
 	  where
 		base = replace "/" "_" $ fromUUID (externalUUID external) ++ "-" ++ setting
+			
+	withurl mk uri = handleRemoteRequest $ mk $
+		setDownloader (show uri) OtherDownloader
 
 sendMessage :: Sendable m => ExternalLock -> External -> m -> Annex ()
 sendMessage lck external m = 
diff --git a/Remote/External/Types.hs b/Remote/External/Types.hs
--- a/Remote/External/Types.hs
+++ b/Remote/External/Types.hs
@@ -43,6 +43,7 @@
 import qualified Utility.SimpleProtocol as Proto
 
 import Control.Concurrent.STM
+import Network.URI
 
 -- If the remote is not yet running, the ExternalState TMVar is empty.
 data External = External
@@ -182,6 +183,8 @@
 	| GETSTATE Key
 	| SETURLPRESENT Key URLString
 	| SETURLMISSING Key URLString
+	| SETURIPRESENT Key URI
+	| SETURIMISSING Key URI
 	| GETURLS Key String
 	| DEBUG String
 	deriving (Show)
@@ -202,6 +205,8 @@
 	parseCommand "GETSTATE" = Proto.parse1 GETSTATE
 	parseCommand "SETURLPRESENT" = Proto.parse2 SETURLPRESENT
 	parseCommand "SETURLMISSING" = Proto.parse2 SETURLMISSING
+	parseCommand "SETURIPRESENT" = Proto.parse2 SETURIPRESENT
+	parseCommand "SETURIMISSING" = Proto.parse2 SETURIMISSING
 	parseCommand "GETURLS" = Proto.parse2 GETURLS
 	parseCommand "DEBUG" = Proto.parse1 DEBUG
 	parseCommand _ = Proto.parseFail
@@ -288,3 +293,7 @@
 	  where
 		go c (url:sz:f:rest) = go ((url, readish sz, f):c) rest
 		go c _ = reverse c
+
+instance Proto.Serializable URI where
+	serialize = show
+	deserialize = parseURI
diff --git a/Remote/GCrypt.hs b/Remote/GCrypt.hs
--- a/Remote/GCrypt.hs
+++ b/Remote/GCrypt.hs
@@ -10,7 +10,8 @@
 	chainGen,
 	getGCryptUUID,
 	coreGCryptId,
-	setupRepo
+	setupRepo,
+	accessShellConfig,
 ) where
 
 import qualified Data.Map as M
@@ -265,17 +266,19 @@
 
 	denyNonFastForwards = "receive.denyNonFastForwards"
 
-isShell :: Remote -> Bool
-isShell r = case method of
+accessShell :: Remote -> Bool
+accessShell = accessShellConfig . gitconfig
+
+accessShellConfig :: RemoteGitConfig -> Bool
+accessShellConfig c = case method of
 	AccessShell -> True
 	_ -> False
   where
-	method = toAccessMethod $ fromMaybe "" $
-		remoteAnnexGCrypt $ gitconfig r
+	method = toAccessMethod $ fromMaybe "" $ remoteAnnexGCrypt c
 
 shellOrRsync :: Remote -> Annex a -> Annex a -> Annex a
 shellOrRsync r ashell arsync
-	| isShell r = ashell
+	| accessShell r = ashell
 	| otherwise = arsync
 
 {- Configure gcrypt to use the same list of keyids that
@@ -319,7 +322,7 @@
 			let destdir = parentDir $ gCryptLocation r k
 			Remote.Directory.finalizeStoreGeneric tmpdir destdir
 			return True
-	| Git.repoIsSsh (repo r) = if isShell r
+	| Git.repoIsSsh (repo r) = if accessShell r
 		then fileStorer $ \k f p -> Ssh.rsyncHelper (Just p)
 			=<< Ssh.rsyncParamsRemote False r Upload k f Nothing
 		else fileStorer $ Remote.Rsync.store rsyncopts
@@ -330,7 +333,7 @@
 	| not $ Git.repoIsUrl (repo r) = byteRetriever $ \k sink ->
 		guardUsable (repo r) (return False) $
 			sink =<< liftIO (L.readFile $ gCryptLocation r k)
-	| Git.repoIsSsh (repo r) = if isShell r
+	| Git.repoIsSsh (repo r) = if accessShell r
 		then fileRetriever $ \f k p ->
 			unlessM (Ssh.rsyncHelper (Just p) =<< Ssh.rsyncParamsRemote False r Download k f Nothing) $
 				error "rsync failed"
diff --git a/Remote/Git.hs b/Remote/Git.hs
--- a/Remote/Git.hs
+++ b/Remote/Git.hs
@@ -49,7 +49,7 @@
 import Remote.Helper.Messages
 import qualified Remote.Helper.Ssh as Ssh
 import qualified Remote.GCrypt
-import Config.Files
+import Annex.Path
 import Creds
 import Annex.CatFile
 
@@ -499,7 +499,7 @@
 			Nothing -> return False
 			Just (c, ps) -> batchCommand c ps
 	| otherwise = return $ do
-		program <- readProgramFile
+		program <- programPath
 		r' <- Git.Config.read r
 		environ <- getEnvironment
 		let environ' = addEntries 
diff --git a/Remote/Helper/Encryptable.hs b/Remote/Helper/Encryptable.hs
--- a/Remote/Helper/Encryptable.hs
+++ b/Remote/Helper/Encryptable.hs
@@ -20,13 +20,14 @@
 ) where
 
 import qualified Data.Map as M
+import qualified "dataenc" Codec.Binary.Base64 as B64
+import Data.Bits.Utils
 
 import Common.Annex
 import Types.Remote
 import Crypto
 import Types.Crypto
 import qualified Annex
-import Utility.Base64
 
 -- Used to ensure that encryption has been set up before trying to
 -- eg, store creds in the remote config that would need to use the
@@ -137,9 +138,9 @@
 
 {- Stores an StorableCipher in a remote's configuration. -}
 storeCipher :: RemoteConfig -> StorableCipher -> RemoteConfig
-storeCipher c (SharedCipher t) = M.insert "cipher" (toB64 t) c
+storeCipher c (SharedCipher t) = M.insert "cipher" (toB64bs t) c
 storeCipher c (EncryptedCipher t _ ks) =
-	M.insert "cipher" (toB64 t) $ M.insert "cipherkeys" (showkeys ks) c
+	M.insert "cipher" (toB64bs t) $ M.insert "cipherkeys" (showkeys ks) c
   where
 	showkeys (KeyIds l) = intercalate "," l
 
@@ -149,11 +150,11 @@
 			M.lookup "cipherkeys" c,
 			M.lookup "encryption" c) of
 	(Just t, Just ks, encryption) | maybe True (== "hybrid") encryption ->
-		Just $ EncryptedCipher (fromB64 t) Hybrid (readkeys ks)
+		Just $ EncryptedCipher (fromB64bs t) Hybrid (readkeys ks)
 	(Just t, Just ks, Just "pubkey") ->
-		Just $ EncryptedCipher (fromB64 t) PubKey (readkeys ks)
+		Just $ EncryptedCipher (fromB64bs t) PubKey (readkeys ks)
 	(Just t, Nothing, encryption) | maybe True (== "shared") encryption ->
-		Just $ SharedCipher (fromB64 t)
+		Just $ SharedCipher (fromB64bs t)
 	_ -> Nothing
   where
 	readkeys = KeyIds . split ","
@@ -169,3 +170,14 @@
 			PubKey -> Nothing
 			Hybrid -> Just "(hybrid mode)"
 		]
+
+{- Not using Utility.Base64 because these "Strings" are really
+ - bags of bytes and that would convert to unicode and not roung-trip
+ - cleanly. -}
+toB64bs :: String -> String
+toB64bs = B64.encode . s2w8
+
+fromB64bs :: String -> String
+fromB64bs s = fromMaybe bad $ w82s <$> B64.decode s
+  where
+	bad = error "bad base64 encoded data"
diff --git a/RemoteDaemon/Transport.hs b/RemoteDaemon/Transport.hs
--- a/RemoteDaemon/Transport.hs
+++ b/RemoteDaemon/Transport.hs
@@ -9,6 +9,7 @@
 
 import RemoteDaemon.Types
 import qualified RemoteDaemon.Transport.Ssh
+import qualified RemoteDaemon.Transport.GCrypt
 import qualified Git.GCrypt
 
 import qualified Data.Map as M
@@ -19,5 +20,5 @@
 remoteTransports :: M.Map TransportScheme Transport
 remoteTransports = M.fromList
 	[ ("ssh:", RemoteDaemon.Transport.Ssh.transport)
-	, (Git.GCrypt.urlScheme, RemoteDaemon.Transport.Ssh.transport)
+	, (Git.GCrypt.urlScheme, RemoteDaemon.Transport.GCrypt.transport)
 	]
diff --git a/RemoteDaemon/Transport/GCrypt.hs b/RemoteDaemon/Transport/GCrypt.hs
new file mode 100644
--- /dev/null
+++ b/RemoteDaemon/Transport/GCrypt.hs
@@ -0,0 +1,27 @@
+{- git-remote-daemon, gcrypt transport
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module RemoteDaemon.Transport.GCrypt (transport) where
+
+import Common.Annex
+import RemoteDaemon.Types
+import RemoteDaemon.Common
+import RemoteDaemon.Transport.Ssh (transportUsingCmd)
+import Git.GCrypt
+import Remote.Helper.Ssh
+import Remote.GCrypt (accessShellConfig)
+
+transport :: Transport
+transport rr@(RemoteRepo r gc) url h@(TransportHandle g _) ichan ochan
+	| accessShellConfig gc = do
+		r' <- encryptedRemote g r
+		v <- liftAnnex h $ git_annex_shell r' "notifychanges" [] []
+		case v of
+			Nothing -> noop
+			Just (cmd, params) -> 
+				transportUsingCmd cmd params rr url h ichan ochan
+	| otherwise = noop
diff --git a/RemoteDaemon/Transport/Ssh.hs b/RemoteDaemon/Transport/Ssh.hs
--- a/RemoteDaemon/Transport/Ssh.hs
+++ b/RemoteDaemon/Transport/Ssh.hs
@@ -5,7 +5,7 @@
  - Licensed under the GNU GPL version 3 or higher.
  -}
 
-module RemoteDaemon.Transport.Ssh (transport) where
+module RemoteDaemon.Transport.Ssh (transport, transportUsingCmd) where
 
 import Common.Annex
 import Annex.Ssh
@@ -22,23 +22,24 @@
 import Control.Concurrent.Async
 
 transport :: Transport
-transport rr@(RemoteRepo r gc) url h@(TransportHandle g s) ichan ochan = do
+transport rr@(RemoteRepo r _) url h ichan ochan = do
+	v <- liftAnnex h $ git_annex_shell r "notifychanges" [] []
+	case v of
+		Nothing -> noop
+		Just (cmd, params) -> transportUsingCmd cmd params rr url h ichan ochan
+
+transportUsingCmd :: FilePath -> [CommandParam] -> Transport
+transportUsingCmd cmd params rr@(RemoteRepo r gc) url h@(TransportHandle g s) ichan ochan = do
 	-- enable ssh connection caching wherever inLocalRepo is called
 	g' <- liftAnnex h $ sshOptionsTo r gc g
-	transport' rr url (TransportHandle g' s) ichan ochan
-
-transport' :: Transport
-transport' (RemoteRepo r _) url transporthandle ichan ochan = do
+	let transporthandle = TransportHandle g' s
+	transportUsingCmd' cmd params rr url transporthandle ichan ochan
 
-	v <- liftAnnex transporthandle $ git_annex_shell r "notifychanges" [] []
-	case v of
-		Nothing -> noop
-		Just (cmd, params) -> robustly 1 $
-			connect cmd (toCommand params)
-  where
-	connect cmd params = do
+transportUsingCmd' :: FilePath -> [CommandParam] -> Transport
+transportUsingCmd' cmd params (RemoteRepo r _) url transporthandle ichan ochan =
+	robustly 1 $ do
 		(Just toh, Just fromh, Just errh, pid) <-
-			createProcess (proc cmd params)
+			createProcess (proc cmd (toCommand params))
 			{ std_in = CreatePipe
 			, std_out = CreatePipe
 			, std_err = CreatePipe
@@ -57,7 +58,7 @@
 		void $ waitForProcess pid
 
 		return $ either (either id id) id status
-
+  where
 	send msg = atomically $ writeTChan ochan msg
 
 	fetch = do
@@ -106,7 +107,7 @@
 
 data Status = Stopping | ConnectionClosed
 
-{- Make connection robustly, with exponentioal backoff on failure. -}
+{- Make connection robustly, with exponential backoff on failure. -}
 robustly :: Int -> IO Status -> IO ()
 robustly backoff a = caught =<< catchDefaultIO ConnectionClosed a
   where
diff --git a/Test.hs b/Test.hs
--- a/Test.hs
+++ b/Test.hs
@@ -71,6 +71,7 @@
 import qualified Utility.Scheduled
 import qualified Utility.HumanTime
 import qualified Utility.ThreadScheduler
+import qualified Utility.Base64
 import qualified Command.Uninit
 import qualified CmdLine.GitAnnex as GitAnnex
 #ifndef mingw32_HOST_OS
@@ -163,6 +164,7 @@
 	, testProperty "prop_branchView_legal" Logs.View.prop_branchView_legal
 	, testProperty "prop_view_roundtrips" Annex.View.prop_view_roundtrips
 	, testProperty "prop_viewedFile_rountrips" Annex.View.ViewedFile.prop_viewedFile_roundtrips
+	, testProperty "prop_b64_roundtrips" Utility.Base64.prop_b64_roundtrips
 	]
 
 {- These tests set up the test environment, but also test some basic parts
diff --git a/Types/MetaData.hs b/Types/MetaData.hs
--- a/Types/MetaData.hs
+++ b/Types/MetaData.hs
@@ -224,6 +224,7 @@
 	| DelMeta MetaField MetaValue
 	| SetMeta MetaField MetaValue -- removes any existing values
 	| MaybeSetMeta MetaField MetaValue -- when field has no existing value
+	deriving (Show)
 
 {- Applies a ModMeta, generating the new MetaData.
  - Note that the new MetaData does not include all the 
diff --git a/Utility/Base64.hs b/Utility/Base64.hs
--- a/Utility/Base64.hs
+++ b/Utility/Base64.hs
@@ -1,24 +1,28 @@
-{- Simple Base64 access
+{- Simple Base64 encoding of Strings
  -
  - Copyright 2011 Joey Hess <id@joeyh.name>
  -
  - License: BSD-2-clause
  -}
 
-module Utility.Base64 (toB64, fromB64Maybe, fromB64) where
+module Utility.Base64 (toB64, fromB64Maybe, fromB64, prop_b64_roundtrips) where
 
-import "dataenc" Codec.Binary.Base64
-import Data.Bits.Utils
+import qualified "dataenc" Codec.Binary.Base64 as B64
 import Control.Applicative
 import Data.Maybe
+import qualified Data.ByteString.Lazy as L
+import Data.ByteString.Lazy.UTF8 (fromString, toString)
 
-toB64 :: String -> String		
-toB64 = encode . s2w8
+toB64 :: String -> String	
+toB64 = B64.encode . L.unpack . fromString
 
 fromB64Maybe :: String -> Maybe String
-fromB64Maybe s = w82s <$> decode s
+fromB64Maybe s = toString . L.pack <$> B64.decode s
 
 fromB64 :: String -> String
 fromB64 = fromMaybe bad . fromB64Maybe
   where
 	bad = error "bad base64 encoded data"
+
+prop_b64_roundtrips :: String -> Bool
+prop_b64_roundtrips s = s == fromB64 (toB64 s)
diff --git a/Utility/FileSystemEncoding.hs b/Utility/FileSystemEncoding.hs
--- a/Utility/FileSystemEncoding.hs
+++ b/Utility/FileSystemEncoding.hs
@@ -14,6 +14,8 @@
 	decodeBS,
 	decodeW8,
 	encodeW8,
+	encodeW8NUL,
+	decodeW8NUL,
 	truncateFilePath,
 ) where
 
@@ -25,6 +27,7 @@
 import qualified Data.Hash.MD5 as MD5
 import Data.Word
 import Data.Bits.Utils
+import Data.List.Utils
 import qualified Data.ByteString.Lazy as L
 #ifdef mingw32_HOST_OS
 import qualified Data.ByteString.Lazy.UTF8 as L8
@@ -89,6 +92,9 @@
  - w82c produces a String, which may contain Chars that are invalid
  - unicode. From there, this is really a simple matter of applying the
  - file system encoding, only complicated by GHC's interface to doing so.
+ -
+ - Note that the encoding stops at any NUL in the input. FilePaths
+ - do not normally contain embedded NUL, but Haskell Strings may.
  -}
 {-# NOINLINE encodeW8 #-}
 encodeW8 :: [Word8] -> FilePath
@@ -100,6 +106,17 @@
  - represent the FilePath on disk. -}
 decodeW8 :: FilePath -> [Word8]
 decodeW8 = s2w8 . _encodeFilePath
+
+{- Like encodeW8 and decodeW8, but NULs are passed through unchanged. -}
+encodeW8NUL :: [Word8] -> FilePath
+encodeW8NUL = join nul . map encodeW8 . split (s2w8 nul)
+  where
+	nul = ['\NUL']
+
+decodeW8NUL :: FilePath -> [Word8]
+decodeW8NUL = join (s2w8 nul) . map decodeW8 . split nul
+  where
+	nul = ['\NUL']
 
 {- Truncates a FilePath to the given number of bytes (or less),
  - as represented on disk.
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,48 @@
+git-annex (5.20150317) unstable; urgency=medium
+
+  * fsck: Incremental fsck uses sqlite to store its records, instead
+    of abusing the sticky bit. Existing sticky bits are ignored;
+    incremental fscks started by old versions won't be resumed by
+    this version.
+  * fsck: Multiple incremental fscks of different repos (including remotes)
+    can now be running at the same time in the same repo without it
+    getting confused about which files have been checked for which remotes.
+  * unannex: Refuse to unannex when repo is too new to have a HEAD,
+    since in this case there must be staged changes in the index
+    (if there is anything to unannex), and the unannex code path
+    needs to run with a clean index.
+  * Linux standalone: Set LOCPATH=/dev/null to work around
+    https://ghc.haskell.org/trac/ghc/ticket/7695
+    This prevents localization from working, but git-annex
+    is not localized anyway.
+  * sync: As well as the synced/git-annex push, attempt a
+    git-annex:git-annex push, as long as the remote branch
+    is an ancestor of the local branch, to better support bare git repos.
+    (This used to be done, but it forgot to do it since version 4.20130909.)
+  * When re-execing git-annex, use current program location, rather than
+    ~/.config/git-annex/program, when possible.
+  * Submodules are now supported by git-annex!
+  * metadata: Fix encoding problem that led to mojibake when storing
+    metadata strings that contained both unicode characters and a space
+    (or '!') character.
+  * Also potentially fixes encoding problem when embedding credentials
+    that contain unicode characters.
+  * sync: Fix committing when in a direct mode repo that has no HEAD ref.
+    (For example, a newly checked out git submodule.)
+  * Added SETURIPRESENT and SETURIMISSING to external special remote protocol,
+    useful for things like ipfs that don't use regular urls.
+  * addurl: Added --raw option, which bypasses special handling of quvi,
+    bittorrent etc urls.
+  * git-annex-shell: Improve error message when the specified repository
+    doesn't exist or git config fails for some reason.
+  * fromkey --force: Skip test that the key has its content in the annex.
+  * fromkey: Add stdin mode.
+  * registerurl: New plumbing command for mass-adding urls to keys.
+  * remotedaemon: Fixed support for notifications of changes to gcrypt
+    remotes, which was never tested and didn't quite work before.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 17 Mar 2015 13:02:36 -0400
+
 git-annex (5.20150219) unstable; urgency=medium
 
   * glacier: Detect when the glacier command in PATH is the wrong one,
diff --git a/debian/control b/debian/control
--- a/debian/control
+++ b/debian/control
@@ -59,6 +59,11 @@
 	libghc-gnutls-dev (>= 0.1.4),
 	libghc-xml-types-dev,
 	libghc-async-dev,
+	libghc-persistent-dev,
+	libghc-persistent-template-dev,
+	libghc-persistent-sqlite-dev,
+	libghc-esqueleto-dev,
+	libghc-monad-logger-dev,
 	libghc-feed-dev (>= 0.3.9.2),
 	libghc-regex-tdfa-dev [!mipsel !s390],
 	libghc-regex-compat-dev [mipsel s390],
diff --git a/debian/rules b/debian/rules
--- a/debian/rules
+++ b/debian/rules
@@ -7,7 +7,3 @@
 
 %:
 	dh $@
-
-# Not intended for use by anyone except the author.
-announcedir:
-	@echo ${HOME}/src/git-annex/doc/news
diff --git a/doc/assistant/comment_6_70193bbaa5d60b829d7636748c641104._comment b/doc/assistant/comment_6_70193bbaa5d60b829d7636748c641104._comment
new file mode 100644
--- /dev/null
+++ b/doc/assistant/comment_6_70193bbaa5d60b829d7636748c641104._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawmN1fkq65FL5gtBB6qFmEKWiyl20OutvDI"
+ nickname="Niklaas"
+ subject="window manager on 1st machine"
+ date="2015-03-03T21:30:53Z"
+ content="""
+Not related to git-annex, but I was just wondering: What window manager are you using on the first machine? Looks like a tile windows manager but you are using XFCE?!
+"""]]
diff --git a/doc/bugs/Deleted_files_during_merge.mdwn b/doc/bugs/Deleted_files_during_merge.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/Deleted_files_during_merge.mdwn
@@ -0,0 +1,2130 @@
+### Please describe the problem.
+
+I edited a file on one machine (firefly), which then synced with another (browncoats). browncoats then deleted the changed file and comitted that with the message «git-annex in browncoats». During this time the file was only ever touched on one machine (firefly), never on browncoats (which I turned on after the two commits on firefly had been made, with git annex assistant running). The result is that the file has disappeared and I have to dig through the log and get it from a backup repository. Both machines are running the assistant in direct mode. Both on ext4 in case that matters.
+
+I've included the daemon.log from browncoats (with filenames redacted).
+
+### What steps will reproduce the problem?
+
+Unknown.
+
+### What version of git-annex are you using? On what operating system?
+
+Both are Archlinux 64bit, both running git-annex version 5.20150219-g52daae5 from the standalone 64bit build.
+
+### Please provide any additional information below.
+
+First commit:
+[[!format text """
+Date:   Thu Mar 5 13:24:30 2015 +0100
+
+    git-annex in firefly
+
+diff --git a/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods b/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
+index 5a18c1e..e579681 120000
+--- a/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
++++ b/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
+@@ -1 +1 @@
+-../../../../.git/annex/objects/Kg/v0/SHA256E-s39322--ca7a6d4d84b59d49a699e921438ace0d6c326c9db218a7c99b0b6626cae4b976.ods/SHA256E-s39322--ca7a6d4d84b59d49a699e921438ace0d6c326c9db218a7c99b0b6626cae4b976.ods
+\ No newline at end of file
++../../../../.git/annex/objects/V8/7z/SHA256E-s39378--dfbc693d94beb76e1556ff2aefd87b5b6678b93f03bcb0113e1249872c6f7c71.ods/SHA256E-s39378--dfbc693d94beb76e1556ff2aefd87b5b6678b93f03bcb0113e1249872c6f7c71.ods
+\ No newline at end of file
+"""]]
+
+Second commit:
+[[!format text """
+Date:   Thu Mar 5 13:27:21 2015 +0100
+
+    git-annex in firefly
+
+diff --git a/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods b/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
+index e579681..f7fbb69 120000
+--- a/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
++++ b/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
+@@ -1 +1 @@
+-../../../../.git/annex/objects/V8/7z/SHA256E-s39378--dfbc693d94beb76e1556ff2aefd87b5b6678b93f03bcb0113e1249872c6f7c71.ods/SHA256E-s39378--dfbc693d94beb76e1556ff2aefd87b5b6678b93f03bcb0113e1249872c6f7c71.ods
+\ No newline at end of file
++../../../../.git/annex/objects/0v/kG/SHA256E-s39498--d962b697df05df77275572bc03f18995b47d013708e6b775c700b3092028c54f.ods/SHA256E-s39498--d962b697df05df77275572bc03f18995b47d013708e6b775c700b3092028c54f.ods
+\ No newline at end of file
+"""]]
+
+The final commit, now on the remote:
+
+[[!format text """
+Date:   Thu Mar 5 13:34:47 2015 +0100
+
+    git-annex in browncoats
+
+diff --git a/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods b/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
+deleted file mode 120000
+index f7fbb69..0000000
+--- a/Dokument/Dokument/Skule/Sjukepleie-s4/leseliste.ods
++++ /dev/null
+@@ -1 +0,0 @@
+-../../../../.git/annex/objects/0v/kG/SHA256E-s39498--d962b697df05df77275572bc03f18995b47d013708e6b775c700b3092028c54f.ods/SHA256E-s39498--d962b697df05df77275572bc03f18995b47d013708e6b775c700b3092028c54f.ods
+\ No newline at end of file
+"""]]
+
+[[!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
+[2015-03-05 13:32:49 CET] main: starting assistant version 5.20150219-g52daae5
+[2015-03-05 13:32:51 CET] Cronner: Consistency check in progress
+[2015-03-05 13:34:40 CET] TransferScanner: Syncing with firefly, serenity, zoe, river 
+p11-kit: couldn't load module: /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so: /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so: cannot open shared object file: Ingen slik fil eller filkatalog
+p11-kit: couldn't load module: /usr/lib/x86_64-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/x86_64-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: Ingen slik fil eller filkatalog
+Warning: the ECDSA host key for 'firefly' differs from the key for the IP address '10.0.0.17'
+Offending key for IP in /home/zerodogg/.ssh/known_hosts:103
+Matching host key in /home/zerodogg/.ssh/known_hosts:148
+X11 forwarding request failed
+Warning: the ECDSA host key for 'firefly' differs from the key for the IP address '10.0.0.17'
+Offending key for IP in /home/zerodogg/.ssh/known_hosts:103
+Matching host key in /home/zerodogg/.ssh/known_hosts:148
+X11 forwarding request failed on channel 0
+(scanning...) [2015-03-05 13:34:41 CET] Watcher: Performing startup scan
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aep11-kit: couldn't load module: /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so: /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so: cannot open shared object file: Ingen slik fil eller filkatalog
+p11-kit: couldn't load module: /usr/lib/x86_64-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/x86_64-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: Ingen slik fil eller filkatalog
+gpg: Signature made to. 19. feb. 2015 kl. 23.44 +0100 CET using DSA key ID 89C809CB
+gpg: /tmp/git-annex-gpg.tmp.0/trustdb.gpg: trustdb created
+gpg: Good signature from "git-annex distribution signing key (for Joey Hess) <id@joeyh.name>"
+gpg: WARNING: This key is not certified with a trusted signature!
+gpg:          There is no indication that the signature belongs to the owner.
+Primary key fingerprint: 4005 5C6A FD2D 526B 2961  E78F 5EE1 DBA7 89C8 09CB
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+ssh: connect to host river port 22: No route to host
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+From firefly:Documents/annexed
+   66ab32c..decb072  annex/direct/master -> firefly/annex/direct/master
+   7a45b9c..66cf859  git-annex  -> firefly/git-annex
+   94362e9..decb072  master     -> firefly/master
+   66ab32c..decb072  synced/master -> firefly/synced/master
+(checksum...)
+ok
+fsck FILENAME (merging firefly/git-annex into git-annex...)
+(started...) (checksum...)
+ok
+fsck FILENAME From serenity:/home/zerodogg/Documents/annexed
+   7a45b9c..66cf859  synced/git-annex -> serenity/synced/git-annex
+   66ab32c..decb072  synced/master -> serenity/synced/master
+Automatic merge went well; stopped before committing as requested
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+(checksum...)
+ok
+fsck FILENAME [2015-03-05 13:34:47 CET] Committer: Committing changes to git
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME [2015-03-05 13:34:47 CET] Pusher: Syncing with firefly, serenity, zoe, river 
+Warning: the ECDSA host key for 'firefly' differs from the key for the IP address '10.0.0.17'
+Offending key for IP in /home/zerodogg/.ssh/known_hosts:103
+Matching host key in /home/zerodogg/.ssh/known_hosts:148
+(checksum...)
+ok
+fsck FILENAME X11 forwarding request failed on channel 0
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME To zerodogg@firefly:Documents/annexed
+   7a45b9c..510e591  git-annex -> synced/git-annex
+   decb072..0f076c0  annex/direct/master -> synced/master
+(checksum...)
+ok
+fsck FILENAME To serenity:/home/zerodogg/Documents/annexed
+   66cf859..510e591  git-annex -> synced/git-annex
+   decb072..0f076c0  annex/direct/master -> synced/master
+(checksum...)
+ok
+fsck FILENAME [2015-03-05 13:34:49 CET] RemoteControl: Syncing with firefly 
+X11 forwarding request failed
+(checksum...)
+ok
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ssh: connect to host river port 22: No route to host
+ssh: connect to host rivefatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+r port 22: No route to host
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+(checksum...)
+ok
+fsck FILENAME From firefly:Documents/annexed
+   decb072..0f076c0  annex/direct/master -> firefly/annex/direct/master
+   66cf859..1de4042  git-annex  -> firefly/git-annex
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME Warning: the ECDSA host key for 'firefly' differs from the key for the IP address '10.0.0.17'
+Offending key for IP in /home/zerodogg/.ssh/known_hosts:103
+Matching host key in /home/zerodogg/.ssh/known_hosts:148
+(checksum...)
+ok
+fsck FILENAME X11 forwarding request failed on channel 0
+To zerodogg@firefly:Documents/annexed
+   510e591..1de4042  git-annex -> synced/git-annex
+(checksum...)
+ok
+fsck FILENAME Everything up-to-date
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+ssh: connect to host river port 22: Nfatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+(checksum...)
+ok
+fsck FILENAME git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME fatal: Unable to create '/home/zerodogg/Documents/annexed/.git/refs/heads/synced/git-annex.lock': File exists.
+
+If no other git process is currently running, this probably means a
+git process crashed in this repository earlier. Make sure no other git
+process is running and remove the file manually to continue.
+fatal: The remote end hung up unexpectedly
+fatal: The remote end hung up unexpectedly
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME From zoe:Documents/annexed
+   61b7ec9..1de4042  synced/git-annex -> zoe/synced/git-annex
+   e3b0e2e..0f076c0  synced/master -> zoe/synced/master
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME fra 2013-02-15 00:05:43.png Everything up-to-date
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+ssh: connect to hofatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+st river port 22: No route to host
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME To zerodogg@zoe:Documents/annexed
+   61b7ec9..1de4042  git-annex -> synced/git-annex
+   e3b0e2e..0f076c0  annex/direct/master -> synced/master
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+fatal: Could not read from remote repository.
+
+Please make sure you have the correct access rights
+and the repository exists.
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME Dragonfall/ShadowrunEditor.ini (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME s(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+(checksum...)
+ok
+fsck FILENAME ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
+git-annex-shell: expected repository UUID b158aa97-4b68-4c37-a109-f3df91480185 but found UUID 2a6ccda4-f94c-484f-aefe-ce49c1767eab
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (2).pdf (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ONSDAG.ret (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ONSDAG.ret (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME M_HAVREGRYN.ret (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+(checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME (checksum...)
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+fsck FILENAME ok
+
+  Time limit (5m) reached!
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+ssh: connect to host river port 22: No route to host
+rsync: connection unexpectedly closed (0 bytes received so far) [sender]
+rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.1]
+
+# End of transcript or log.
+"""]]
diff --git a/doc/bugs/Offline_editing_in_Android_removes_files_and_creates_links.mdwn b/doc/bugs/Offline_editing_in_Android_removes_files_and_creates_links.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/Offline_editing_in_Android_removes_files_and_creates_links.mdwn
@@ -0,0 +1,45 @@
+### Please describe the problem.
+Two androids, A and B, and a computer, C. All running git annex assistant.
+If you edit a file on A while A is offline, when A is back online and reconnects, that file will disappear from C and, in B, it will be substituted by a link
+If you create a new file on A, that file will appear as a link in B and in C
+
+
+### What steps will reproduce the problem?
+- Have A, B, and C be connected sharing some repo. Create a file, file1. Let it propagate, so file1 is on A, B, C.
+
+- Take A offline (e.g., turn wifi off).
+
+- Edit file1 in A.
+
+- Create file2 in A.
+
+- (Let those files appear in the repo in A as in
+[2015-02-27 20:55:04 CET] Committer: Adding file1
+add file1 ok
+)
+
+- Turn the wifi of A on again.
+
+- Sync A from the webapp (clik on sync now)
+
+- In B (the other android) both file1 and file2 will contain just links, not the actual content of file1 and file2.
+
+- In the computer, file1 will have disappeared and file2 will be a link that points nowhere. (The link that file2 points too, as a string, are the contents of file2 in B). 
+
+
+
+### What version of git-annex are you using? On what operating system?
+Computer: 5.20141125 
+
+Androids: 5.20150226-g9c72d37 and 5.20150224-g9dca034
+
+
+### 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.
+"""]]
diff --git a/doc/bugs/Unicode_characters_lost__47__converted_in_metadata.mdwn b/doc/bugs/Unicode_characters_lost__47__converted_in_metadata.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/Unicode_characters_lost__47__converted_in_metadata.mdwn
@@ -0,0 +1,17 @@
+### Please describe the problem.
+
+Unicode characters in metadata are pruned/converted/lost:
+
+    % git annex metadata -s caption='Unicode → … characters' test.W1z7M7.txt
+    metadata test.W1z7M7.txt
+      caption=Unicode  & characters
+      caption-lastchanged=2015-03-04@08-55-26
+      lastchanged=2015-03-04@08-55-26
+    ok
+    (Recording state in git...)
+
+### What version of git-annex are you using? On what operating system?
+
+5.20141125 Debian
+
+> [[fixed|done]]; test pass. --[[Joey]]
diff --git a/doc/bugs/Update_freebsd_install_instructions.mdwn b/doc/bugs/Update_freebsd_install_instructions.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/Update_freebsd_install_instructions.mdwn
@@ -0,0 +1,11 @@
+### Please describe the problem.
+
+The install documentation is out of date at least for the FreeBSD example.
+
+### Please provide any additional information below.
+
+Latest FreeBSD 10.x uses pkgng instead of pkg_add and the correct command is now 'pkg install hs-git-annex'.
+
+If you find the time please update it at https://git-annex.branchable.com/install/ .
+
+[[done]]
diff --git a/doc/bugs/adding_remote_server_using_ssh_on_a_4.1_device.mdwn b/doc/bugs/adding_remote_server_using_ssh_on_a_4.1_device.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/adding_remote_server_using_ssh_on_a_4.1_device.mdwn
@@ -0,0 +1,36 @@
+[[!meta title="adding remote server using ssh on an Android 4.1 device"]]
+
+### Please describe the problem.
+
+Unable to add remote server using ssh on a 4.1 device.
+
+The error message on the android is: Failed to ssh to the server. Transcript: Could not create directory '(null)/.ssh'.
+
+The message from sshd on the server is: Feb 20 11:32:37 thrain sshd[1662]: Did not receive identification string from 10.1.0.16
+
+(thrain is the sshd server, 10.1.0.16 is the android)
+
+### What steps will reproduce the problem?
+
+On the android, go into the get-annex webpage, select add remote repository,
+add the particulars
+
+hit check this server.
+
+### What version of git-annex are you using? On what operating system?
+
+The android version of git-annex is 5.20150219-gd24cgd3
+The version of address is 4.1.1
+
+The sshd server is debian wheezy
+
+
+### 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.
+"""]]
diff --git a/doc/bugs/android_ed25519_algorithm.mdwn b/doc/bugs/android_ed25519_algorithm.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/android_ed25519_algorithm.mdwn
@@ -0,0 +1,12 @@
+### Please describe the problem.
+Openssh was not compiled to support ed25519 algorithm
+
+### What steps will reproduce the problem?
+only enable ed25519 on server and try to connect via ssh.
+fails with "no hostkey alg"
+
+### What version of git-annex are you using? On what operating system?
+5.20150219-gd24cfd3, Android 5.0.1
+
+regards,
+David
diff --git a/doc/bugs/assistant_report_error_when_git_global_email+name_not_set.mdwn b/doc/bugs/assistant_report_error_when_git_global_email+name_not_set.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/assistant_report_error_when_git_global_email+name_not_set.mdwn
@@ -0,0 +1,23 @@
+### Please describe the problem.
+When setting git-annex on a device (a mac at least in my case), where git has never been used, you get a cryptic git error in the assistant which prevents you to create your first repo.
+Going to the terminal and running git --global for email and name solved the problem.
+
+
+### What steps will reproduce the problem?
+
+
+### What version of git-annex are you using? On what operating system?
+
+
+### 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.
+"""]]
+
+> [[closing|done]] since no version was provided and the current version
+> almost certianly deals with this. --[[Joey]]
diff --git a/doc/bugs/encryption__61__none_doesn__39__t_work_with_enableremote.mdwn b/doc/bugs/encryption__61__none_doesn__39__t_work_with_enableremote.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/encryption__61__none_doesn__39__t_work_with_enableremote.mdwn
@@ -0,0 +1,42 @@
+### Please describe the problem.
+When cloning a remote client repo via ssh and then enableremote the encryptionsetting seem not be used
+
+
+### What steps will reproduce the problem?
+- create a repository (as client) on computer WO
+- create a special remote via rsync+ssh on computer BA with encryption=none from WO
+--> syncing works
+- git clone via ssh from WO on computer XY, group is manual
+- git-annex get on XY with source WO workes (OK)
+- enableremote BA on computer XY
+- shutdown computer WO
+- try to get some file on computer XY. The download is first tried from WO, then from BA  --> correct
+
+
+- download from BA fails (ERROR) 
+--> Reason seems to be that encryption=none is not honored: 
+rsync: change_dir "XXXXXXXX/GPGHMACSHA1--398057f8bd37edf898aeae4557c6277f1162382b" failed: No such file or directory (2)
+
+I additionally could not find out where to manually change the encryption settings after enableremote
+
+
+
+### What version of git-annex are you using? On what operating system?
+git-annex version: 5.20140412ubuntu1
+build flags: Assistant Webapp Webapp-secure Pairing Testsuite S3 WebDAV Inotify DBus DesktopNotify XMPP 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: 0 1 2 4
+
+
+### 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.
+"""]]
diff --git a/doc/bugs/false_positives_from_fsck_in_bare_repo.mdwn b/doc/bugs/false_positives_from_fsck_in_bare_repo.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/false_positives_from_fsck_in_bare_repo.mdwn
@@ -0,0 +1,45 @@
+### Please describe the problem.
+
+git annex fsck complains about no known copies of files which seem to be there
+
+### What steps will reproduce the problem?
+
+run git annex fsck in a bare repo? At least I tried 3, two from one set of mirrors, and one from another
+
+### What version of git-annex are you using? On what operating system?
+
+╰─% apt-cache policy git-annex
+git-annex:
+  Installed: 5.20141125
+  Candidate: 5.20141125
+  Version table:
+ *** 5.20141125 0
+        900 http://http.debian.net/debian/ jessie/main amd64 Packages
+
+
+### 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
+$ cd /media/usbdata3/data/audio.git/
+$ tail /tmp/usbdata3.audio.log
+  ** No known copies exist of SHA256E-s22382--ceaa24fd4ef186b90146cbfc48a2da261e85d63288520aa3efd80705f1976117.jpg
+  ** No known copies exist of SHA256E-s6532--4cf24963db72d1c06b03310a83922875bfff4d82b7285096a7bf76ecdba39552.jpg
+  ** No known copies exist of SHA256E-s9539--eb1db62f33125aee2093ecf530f94497f8c890b3ffddb5214cbd2ad99ce5a4c4.jpg
+  ** No known copies exist of SHA256E-s13710--5d69a49a290012f480e6848f88122e90f803177c610524234e16136d95bc7715.jpg
+  ** No known copies exist of SHA256E-s3515--3a225ae6b26571a27d7e70f49948e2be4d78f1fb29e64308880e208e20bc2868.jpg
+  ** No known copies exist of SHA256E-s8359--9291d7b0bf3a862901607ec7c56d5e1ee6a0f3889e775e4db23999b38322e83f.jpg
+  ** No known copies exist of SHA256E-s3157--4c43cf5618f939a09dada21b45b3860bcb4c6968fa166daf3215f879a25e504d.gif
+  ** No known copies exist of SHA256E-s2676--13b4b08525ce90b44ea9eb703630646f2d8f41d9a07b65d130aaf653a072d408.gif
+  ** No known copies exist of SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg
+git-annex: fsck: 10484 failed
+$ find . -name SHA256E-s5863--f0eb8c34ea1aa834280c7\*
+./annex/objects/5b3/5c3/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg
+./annex/objects/5b3/5c3/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg
+$ sha256sum ./annex/objects/5b3/5c3/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg
+f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746  ./annex/objects/5b3/5c3/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg/SHA256E-s5863--f0eb8c34ea1aa834280c78f1ec28d50aef81379ba62fb0bbf084664c7a7e2746.jpg
+$ 
+
+# End of transcript or log.
+"""]]
diff --git a/doc/bugs/git-annex_on_NAS_eats_all_memory.mdwn b/doc/bugs/git-annex_on_NAS_eats_all_memory.mdwn
--- a/doc/bugs/git-annex_on_NAS_eats_all_memory.mdwn
+++ b/doc/bugs/git-annex_on_NAS_eats_all_memory.mdwn
@@ -33,3 +33,7 @@
 
 # End of transcript or log.
 """]]
+
+> Went ahead with setting LOCPATH=/dev/null in runshell, so it won't
+> run into whatever problem with the locales is causing it to hit this GHC
+> bug. [[done]] (I hope) --[[Joey]]
diff --git a/doc/bugs/git.kitenet.net__47__downloads_has_wrong_git-annex_branch.mdwn b/doc/bugs/git.kitenet.net__47__downloads_has_wrong_git-annex_branch.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/git.kitenet.net__47__downloads_has_wrong_git-annex_branch.mdwn
@@ -0,0 +1,58 @@
+### Please describe the problem.
+
+This is coming from [[main repo not available on downloads.kitenet.net]], probably was the original issue, but since I already create a duplicate there, I won't assume anything (sorry about that!).
+
+### What steps will reproduce the problem?
+
+I am not sure. I know that I had an external drive with a clone of *some* repo related to `downloads.kitenet.net`. Doing a `git annex get` wouldn't work:
+
+<pre>
+anarcat@marcos:current$ cd /media/anarcat/VHS/downloads.kitenet.net/git-annex/linux/current/
+anarcat@marcos:current$ git annex get git-annex-standalone-amd64.tar.gz
+get git-annex-standalone-amd64.tar.gz (not available)
+  Try making some of these repositories available:
+        840760dc-08f0-11e2-8c61-576b7e66acfd -- main repo
+        d7fa24ad-d104-4064-ad10-1078a4436e72 -- joey@elephant:~/lib/downloads
+failed
+git-annex: get: 1 failed
+anarcat@marcos:current$ git remote -v
+origin  git://git.kitenet.net/downloads.git (fetch)
+origin  git://git.kitenet.net/downloads.git (push)
+</pre>
+
+it turns out i somehow managed to checkout from `git://git.kitenet.net/downloads.git`. I don't know where I got this URL from, may it was back when I created that other bug report and the git URL wasn't explicitely mentionned on http://downloads.kitenet.net/ It turns out that there's a `git-annex` branch there that diverged from the "real" one, and is lacking tracking information. changing the remote here fixed the problem:
+
+<pre>
+anarcat@marcos:current$ git remote set-url origin http://downloads.kitenet.net/.git/
+anarcat@marcos:current$ git remote update
+Récupération de origin
+Depuis http://downloads.kitenet.net/
+ + e9febdc...1a80292 git-annex  -> origin/git-annex  (mise à jour forcée)
+anarcat@marcos:current$ git annex get git-annex-standalone-amd64.tar.gz
+get git-annex-standalone-amd64.tar.gz (from origin...) --2015-02-26 18:40:47--  http://downloads.kitenet.net/.git//annex/objects/Pm/8Z/SHA256E-s45589010--f82e2f600763b0f25a45a96ddf7ed68f26c67122e22cf8833d4c2473475bbce2.tar.gz/SHA256E-s45589010--f82e2f600763b0f25a45a96ddf7ed68f26c67122e22cf8833d4c2473475bbce2.tar.gz
+Résolution de downloads.kitenet.net (downloads.kitenet.net)… 66.228.36.95, 2600:3c03::f03c:91ff:fe73:b0d2
+Connexion à downloads.kitenet.net (downloads.kitenet.net)|66.228.36.95|:80… connecté.
+requête HTTP transmise, en attente de la réponse… 200 OK
+[...]
+</pre>
+
+### What version of git-annex are you using? On what operating system?
+
+5.20141125 on debian jessie.
+
+Sorry for the noise in that other bug report! I really thought it was the same issue .... --[[anarcat]]
+
+> The repository has a synced/git-annex that is newer, so it will be
+> available if using git-annex sync.
+> 
+> It looks like git-annex sync has not pushed git-annex:git-annex since
+> [[!commit 6cdac3a003b6850fd96a60d94320d084d8651096]]. I think that commit might
+> have removed that accidentially; I can't tell for sure. 
+> 
+> Adding git-annex:git-annex
+> to the direct push would avoid this problem. Long as that push is not
+> forced, there's no risk of overwriting other changes to the git-annex
+> branch. (Even if it does get overwritten, there's no data loss; things
+> will get into sync eventually.)
+> 
+> So, I've added back the git-annex:git-annex push. [[done]] --[[Joey]]
diff --git a/doc/bugs/incremental_fsck_should_not_use_sticky_bit.mdwn b/doc/bugs/incremental_fsck_should_not_use_sticky_bit.mdwn
--- a/doc/bugs/incremental_fsck_should_not_use_sticky_bit.mdwn
+++ b/doc/bugs/incremental_fsck_should_not_use_sticky_bit.mdwn
@@ -15,3 +15,5 @@
 Debian's 4.20131106~bpo70+1
 
 [[!tag confirmed]]
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/bugs/make_whereis_output_more_concise.mdwn b/doc/bugs/make_whereis_output_more_concise.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/make_whereis_output_more_concise.mdwn
@@ -0,0 +1,60 @@
+### Please describe the problem.
+
+annex  lists all the remotes UUIDs (the same) when whereis is ran across multiple files.  This makes output lengthy and harder to process and share for no reason.  Why not to list remotes just once on top and then only locations per each file, e.g. instead of 
+[[!format sh """
+
+$> git annex whereis       
+whereis 2011-Palmour-etal_canadian_consent_forms.pdf (2 copies) 
+  	00000000-0000-0000-0000-000000000001 -- web
+   	94b3c553-ad30-450e-be56-504b400f9a5c -- yoh@novo:~/proj/open-consent [here]
+
+  web: http://download.springer.com/static/pdf/638/art%253A10.1186%252F1472-6939-12-1.pdf?auth66=1401467160_8992951c5cccc0dbe510c369eba3afa1&ext=.pdf
+ok
+whereis Arizona_consent.pdf (2 copies) 
+  	00000000-0000-0000-0000-000000000001 -- web
+   	94b3c553-ad30-450e-be56-504b400f9a5c -- yoh@novo:~/proj/open-consent [here]
+
+  web: http://web.arizona.edu/~arg/papers/fmri/forms/consent.pdf
+ok
+
+"""]]
+
+get (not sure if I want to see ok much either)
+
+[[!format sh """
+
+$> git annex whereis       
+  	00000000-0000-0000-0000-000000000001 -- web
+   	94b3c553-ad30-450e-be56-504b400f9a5c -- yoh@novo:~/proj/open-consent [here]
+
+whereis 2011-Palmour-etal_canadian_consent_forms.pdf (2 copies) 
+  web: http://download.springer.com/static/pdf/638/art%253A10.1186%252F1472-6939-12-1.pdf?auth66=1401467160_8992951c5cccc0dbe510c369eba3afa1&ext=.pdf
+
+whereis Arizona_consent.pdf (2 copies) 
+  web: http://web.arizona.edu/~arg/papers/fmri/forms/consent.pdf
+"""]]
+
+
+### What steps will reproduce the problem?
+
+run git annex whereis on a directory with multiple files
+
+### What version of git-annex are you using? On what operating system?
+
+Debian
+[[!format sh """
+$> acpolicy git-annex
+git-annex:
+  Installed: 5.20150205+git57-gc05b522-1~nd80+1
+  Candidate: 5.20150205+git57-gc05b522-1~nd80+1
+  Version table:
+ *** 5.20150205+git57-gc05b522-1~nd80+1 0
+        500 http://neuro.debian.net/debian-devel/ jessie/main amd64 Packages
+        100 /var/lib/dpkg/status
+"""]]
+
+> See `git annex list`, which comes right after `whereis` in the
+> man page, and is described as "similar to whereis but a more compact
+> display".
+>
+> [[done]] --[[Joey]]
diff --git a/doc/bugs/provide_--version_.mdwn b/doc/bugs/provide_--version_.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/provide_--version_.mdwn
@@ -0,0 +1,5 @@
+### Please describe the problem.
+
+I see no easy way to determine version of git-annex (besides as of the debian package).  git annex is not aware of "git annex --version" either
+
+[[done]]
diff --git a/doc/bugs/unannex_requires_commit_for_new_directories.mdwn b/doc/bugs/unannex_requires_commit_for_new_directories.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/bugs/unannex_requires_commit_for_new_directories.mdwn
@@ -0,0 +1,31 @@
+### Please describe the problem.
+"git-annex unannex" requires an unexpected (and undesirable) commit only when adding files in a new directory. This is undesirable because whenever "git-annex add" is accidentally run in a new directory, the only way to undo it is to commit first and then unannex, which adds two unwanted commits to the git log. Moreover, this behavior is not consistent with unannex on files in non-new directories: in that case unannex works as expected.
+
+### What steps will reproduce the problem?
+<pre><code>/tmp> mkdir test
+/tmp> cd test/
+/tmp/test> git init 
+Initialized empty Git repository in /tmp/test/.git/
+/tmp/test (master)> git annex init
+init  ok
+(recording state in git...)
+/tmp/test (master)> touch foo
+/tmp/test (master)> git annex add foo
+add foo ok
+(recording state in git...)
+/tmp/test (master)> git annex unannex foo
+unannex foo ok
+/tmp/test (master)> mkdir bar
+/tmp/test (master)> touch bar/foo
+/tmp/test (master)> git annex add bar
+add bar/foo ok
+(recording state in git...)
+/tmp/test (master)> git annex unannex bar
+git-annex: Cannot proceed with uncommitted changes staged in the index. Recommend you: git commit
+</code></pre>
+
+
+### What version of git-annex are you using? On what operating system?
+The issue occurs with last version of git-annex, available at the time of this post (2015-02-19 16:20). I could reproduce the issue in all other versions of git-annex I tried (not many though). I am using Linux, Ubuntu 12.04 amd64.
+
+> [[done]]; added check for repository too new to have a HEAD. --[[Joey]]
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 12 "Amazon Glacier (done)" 10 "Box.com (done)" 74 "My phone (or MP3 player)" 25 "Tahoe-LAFS" 14 "OpenStack SWIFT" 36 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 74 "My phone (or MP3 player)" 25 "Tahoe-LAFS" 16 "OpenStack SWIFT" 36 "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
diff --git a/doc/design/caching_database.mdwn b/doc/design/caching_database.mdwn
--- a/doc/design/caching_database.mdwn
+++ b/doc/design/caching_database.mdwn
@@ -25,7 +25,7 @@
 
 ## implementation plan
 
-1. Store incremental fsck info in db, on a branch, with sqlite.
+1. Store incremental fsck info in db, on a branch, with sqlite. **done**
 2. Make sure that builds on all platforms.
 3. Implement for metadata, on a branch, with sqlite.
 4. Add associated file mappings support. This is needed to fully
@@ -148,3 +148,9 @@
 For metadata, the story is much nicer. Querying for 30000 keys that all
 have a particular tag in their metadata takes 0.65s. So fast enough to be
 used in views.
+
+Update4: Comparing git-annex fsck using the sticky bit to the final sqlite
+implementation:
+
+sticky bit: 4m30.787s  
+sqlite: 4m40.789s  
diff --git a/doc/design/external_special_remote_protocol.mdwn b/doc/design/external_special_remote_protocol.mdwn
--- a/doc/design/external_special_remote_protocol.mdwn
+++ b/doc/design/external_special_remote_protocol.mdwn
@@ -274,10 +274,19 @@
   Gets any state that has been stored for the key.  
   (git-annex replies with VALUE followed by the state.)
 * `SETURLPRESENT Key Url`  
-  Records an url (or uri) where the Key can be downloaded from.
+  Records an URL where the Key can be downloaded from.
 * `SETURLMISSING Key Url`  
   Records that the key can no longer be downloaded from the specified
-  url (or uri).
+  URL.
+* `SETURIPRESENT Key Uri`  
+  Records a special URI where the Key can be downloaded from.  
+  For example, "ipfs:ADDRESS" is used for the ipfs special remote;
+  its CLAIMURL handler checks for such URIS and claims them. Setting
+  it present as an URI makes `git annex whereis` display the URI
+  as belonging to the special remote.
+* `SETURIMISSING Key Uri`  
+  Records that the key can no longer be downloaded from the specified
+  URI.
 * `GETURLS Key Prefix`  
   Gets the recorded urls where a Key can be downloaded from.
   Only urls that start with the Prefix will be returned. The Prefix
diff --git a/doc/design/iabackup.mdwn b/doc/design/iabackup.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/design/iabackup.mdwn
@@ -0,0 +1,240 @@
+This is a fairly detailed design proposal for using git-annex to build
+<http://archiveteam.org/index.php?title=INTERNETARCHIVE.BAK>
+
+[[!toc ]]
+
+## end-user view
+
+What the end user sees is a directory, with a .git subdirectory,
+and 100 thousand little files (actually, they're broken symlinks, on
+Linux/OSX). Over time, some of the symlinks start filling in with
+"random" content from the IA. 
+
+The user can look at that content, or even delete files they don't want to
+host.
+
+The user can control how much total disk space the directory takes up.
+(It will use around 100 mb when empty.)
+
+## sharding to scale
+
+The IA contains some 14 million Items. Inside these Items are 271 million
+files. Around 177 million of those are available for download.
+
+git repositories do not scale well in the 1-10 million file 
+range, and very badly above that. Storing all that in a git repository
+would strain git's scalability badly.
+
+Solution: Create multiple git repositories, and split the files
+amoung them.
+
+* If each git repository holds 100 thousand files, that is 1770
+  repositories, which is not an unmanagable number. 
+  (For comparison, git.debian.org has 18500 repositories.)
+
+* The IA is ~20 Petabytes large. Each shard would thus be around 1
+  terabyte in size, although this will vary considerably.
+
+* Clients are assigned one or more shards, and clone those repositories.
+
+* A client decides which files in its shard to back up, and does
+  so by running "git annex get" on them. This downloads the files
+  over http from the IA.
+
+* A client will typically not back up its entire shard, but maybe
+  only 500 gb or less of it. Also, we want redundancy (LOCKSS)
+  -- say at least 3 copies of each file. So, a given shard will probably
+  have between 3 and 9 clients handling it.
+
+* Add new shards as the IA continues to grow.
+
+Problem: Need to get the checksums for the files, for git-annex
+to use. The census published by the IA only has md5sums in it. While
+git-annex can use md5sums, this allows bad actors to find md5 collisions
+with files from the archive, and upload bogus files that checksum ok
+when restoring.
+
+## creating a shard
+
+This is a simple matter of making a git repository and telling git-annex
+the filenames and urls that belong in it.
+
+A script can do this using the `git annex fromkey` and `git annex
+registerurl` commands. Time to make such a repository with 100k files
+is in the 10 minute range (faster on SSD or randisk).
+
+## adding a client
+
+When a client registers to participate:
+
+1. Generate a UUID, which is assigned to this client, and send it to the
+   client, and assign that UUID to a particular shard.
+2. Send the client an appropriate auth token (eg, a locked down ssh private
+   key) to let them access the shard's git repository (or all the shards).
+3. Client clones its assigned shard git repository,
+   runs `git annex init reinit $UUID`.
+
+Note that a client could be assigned to multiple shards, rather than just
+one. Probably good to keep a pool of empty shards that have clients waiting
+for new files to be added.
+
+Note that we may want to enable direct mode in the client's clone, 
+because it lets the user easily delete files to free up space.
+OTOH, direct mode is slow and less safe, so we might prefer to use indirect
+mode, and then the client would need to use `git annex drop` if they
+decided to remove content.
+
+## distributing files
+
+1. Client runs `git annex sync --content`, which downloads as many
+   files from the IA as will fit in their disk's free space
+   (leaving some configurable amount free in reserve by configuring
+   annex.diskreserve)
+2. Note that [[numcopies|copies]] and [[preferred_content]] settings can be
+   used to make clients only want to download an file if it's not yet
+   reached the desired number of copies. Lots of flexability here in
+   git-annex.
+3. git-annex will push back to the server an updated git-annex branch,
+   which will record when it has successfully stored an file.
+
+## bad actors
+
+Clients can misbehave in probably many ways. The best defense for many
+misbehaviors is to distribute files to enough different clients that we can
+trust some of them.
+
+The main git-annex specific misbehavior is that a client could try to push
+garbage information back to the origin repository on the server.
+
+To guard against this, the server will reject all pushes of branches other
+than the git-annex branch, which is the only one clients need to modify.
+
+Check pushes of the git-annex branch. There are only a few files that
+clients can legitimately modify, and the modifications will always involve
+that client's UUID, not some other client's UUID. Reject anything shady.
+
+These checks can be done in a git `update` hook. Rough estimate is that
+such a hook would be a couple hundred lines of code.
+
+## verification
+
+We want a lightweight verification process, to verify that a client still
+has the data. This can be done using `git annex fsck`, which can be
+configured to eg, check each file only once per month.
+
+git-annex will need a modification here. Currently, a successful fsck
+does not leave any trace in the git-annex branch that it happened. But
+we want the server to track when a client is not fscking (the user probably
+dropped out).
+
+The modification is simple; just have a successful fsck
+update the timestamp in the fscked file's location log.
+It will probably take just a few hours to code.
+
+With that change, the server can check for files that not enough clients
+have verified they have recently, and distribute them to more clients.
+
+Note that bad actors can lie about this verification; it's not a proof they
+still have the file. But, a bad actor could prove they have a file, and
+refuse to give it back if the IA needed to restore the backup, too.
+
+## fire drill
+
+If we really want to test how well the system is working, we need a fire
+drill.
+
+1. Pick some files that we'll assume the IA has lost in some disaster.
+2. Look up the shard the file belongs to.
+3. Get the git-annex key of the file, and tell git-annex it's been
+   lost from the IA, by running in its shard: `setpresentkey $key $iauuid 0`
+4. The next time a client runs `git annex sync --content`, it will notice
+   that the IA repo doesn't have the file anymore. The client will then
+   send the file back to the origin repo.
+5. To guard against bad actors, that restored file should be checked with
+   `git annex fsck`. If its checksum is good, it can be re-injected back
+   into the IA. (Or, the fire drill was successful.)
+   (Remember to turn off the fire alarm by running
+   `setpresentkey $key $iauuid 1`)
+
+## shard servers
+
+A server at the IA (or otherwise with a fast pipe) is needed to serve
+the shards. One server can probably manage them all.
+Let's consider what this server needs to have on it:
+
+* git and git-annex
+* ssh server
+* The git repository for each shard. A few hundred mb per shard.
+* The git update hook to filter out bad pushes.
+* Some way to learn when a new user has registered to access a shard,
+  so their ssh key is given access.
+
+## other optional nice stuff
+
+The user running a client can delete some or all of their files at any
+time, to free up disk space. The next time `git-annex sync` runs on the client,
+it'll notice and let the server know, and other clients will then take
+over storing it. (Or if the git-annex assistant is run on the client,
+it would inform the server immediately.)
+
+The user is also free to move files around (within the git repository
+directory), modify files, view them, etc. This doesn't affect anyone else.
+
+Offline storage is supported. As long as the user can spin it up from time
+to time to run `git annex fsck`.
+
+More advanced users might have multiple repositories on different disks.
+Each has their own UUID, and they could move files around between them as
+desired; this would be communicated back to the origin repository
+automatically.
+
+Shards could have themes, and users could request to be part of the
+shard that includes Software, or Grateful Dead, etc. This might encourage
+users to devote more resources.
+
+Or, rather than doing a lucky dip and getting one or a couple shards,
+a user could clone em all, and pick just which files to get.
+
+The contents of files sometimes changes.
+This can be reflected by updating the file in the git repository.
+Clients will then download the new version of the file. (They will also
+tend to retain the old version, although this can be dealt with by using
+`git annex unused`).
+
+Items sometimes go dark; this could be reflected by deleting the Item's
+files from the repository. It's up to the clients what they do with the
+content of such Items.
+
+Client's repos could be put into groups to classify them. For example,
+there could be groups per continent, or for trust levels, or whatever.
+These can be used by [[preferred_content]] expressions to fine tune how
+files are spread out amoung the available clients.
+
+## other potential gotchas
+
+If any single file is very large (eg, 10 terabytes), there may not be
+any clients that can handle it. This could be dealt with by splitting up
+the file into smaller chunks. Word is there is a single 2 tb item, and a few
+more around 100 gb, so this is probably not a concern.
+
+A client could add other files to its local repo, and git-annex branch
+pushes would include junk data about those files. It should probably be
+filtered out by the git update hook (rejecting the whole push because of
+this seems excessive).
+
+There may be a thundering herd problem, where many clients end up
+downloading the same file at the same time, and more copies than neecessary
+result. The next `git annex sync --content` in some of the
+redundant clients will notice this and drop that file, and presumably
+download some other file. It would be good to avoid this problem,
+perhaps by having a new client initially download a random set of the
+files in their shard that don't yet have enough copies.
+
+With clients all fscking their part of a shard once a month,
+that will increase the size of the git repository, with new distributed
+fsck updates. I have run some test and this fsck overhead delta compresses
+well. With a 10 thousand file repo and 100 clients all updating the
+location log, the monthly fsck only added 1 mb to the repository size
+(after `git gc --aggressive`). Should scale linearly with number of files
+in repo. Note that `git annex forget` could be used to forget old
+historical data if the repo grew too large from fsck updates.
diff --git a/doc/design/iabackup/comment_1_d33c0910973bc37ce81bf434017e11fd._comment b/doc/design/iabackup/comment_1_d33c0910973bc37ce81bf434017e11fd._comment
new file mode 100644
--- /dev/null
+++ b/doc/design/iabackup/comment_1_d33c0910973bc37ce81bf434017e11fd._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawnx8kHW66N3BqmkVpgtXDlYMvr8TJ5VvfY"
+ nickname="Yaroslav"
+ subject="great to see such a large scale effort ongoing"
+ date="2015-03-06T04:47:30Z"
+ content="""
+and I would still maintain my view that removing intermediate directory withing .git/annex/objects whose  current roles is simply to provide read-only protection might half the burden on the underlying file system, either annex repo(s) are multitude or a single one [1]. lean view [2] could also be of good use as well[2].  Similar exercises with simulated annex'es with >5M files also \"helped\" to identify problems with ZOL (ZFS on Linux) caching suggesting that even mere handling of such vast arrays of tiny files (as dead symlinks) might give filesystems a good test, so the leaner impact would be -- the better.
+
+[1] e.g. https://github.com/datalad/datalad/issues/32#issuecomment-70523036
+[2] https://github.com/datalad/datalad/issues/25
+"""]]
diff --git a/doc/design/iabackup/comment_2_c0a59549409faa355a461e85a1c3f908._comment b/doc/design/iabackup/comment_2_c0a59549409faa355a461e85a1c3f908._comment
new file mode 100644
--- /dev/null
+++ b/doc/design/iabackup/comment_2_c0a59549409faa355a461e85a1c3f908._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawkSq2FDpK2n66QRUxtqqdbyDuwgbQmUWus"
+ nickname="Jimmy"
+ subject="comment 2"
+ date="2015-03-09T16:48:18Z"
+ content="""
+I've tried throwing about ~16 million files at git/git-annex in the past where some files were 1-2kb in size (around 30% of them). git/git-annex doesn't work well at that scale.
+"""]]
diff --git a/doc/design/iabackup/comment_3_560d3f65d543c3af9722ed7e9a11e920._comment b/doc/design/iabackup/comment_3_560d3f65d543c3af9722ed7e9a11e920._comment
new file mode 100644
--- /dev/null
+++ b/doc/design/iabackup/comment_3_560d3f65d543c3af9722ed7e9a11e920._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawmsy_GIefGlGGD_XJp_R6EsWIRUC4ev9XU"
+ nickname="David"
+ subject="This is a BIG task"
+ date="2015-03-13T20:48:56Z"
+ content="""
+If I understand it correctly, 20PB at 2400 shards of 8TB each with 3 copies is 24TB/shard at 1TB/client is 2400*24 = ~60K clients assuming no churn. So it would probably need ~100K clients to cover the churn and have a good chance that each shard had 3 copies at all times. That's 1/3 the size of BOINC's active population.
+
+It would take time to scale to that population. And it would take time to get three copies out of the Archive. During that time, the Archive is growing. The back of my envelope says that doing this in 2.5yrs roughly doubles the Archive's outbound bandwidth if you average it across the 2.5 years. But the population would grow slowly to start with, then faster, so that the bandwidth impact would be back-loaded. And at the end of the 2.5 years, you would need a lot more than the 100K users.
+
+A design that used erasure coding or entanglement would reduce the storage and bandwidth demand considerably while providing adequate reliability.
+
+"""]]
diff --git a/doc/design/roadmap.mdwn b/doc/design/roadmap.mdwn
--- a/doc/design/roadmap.mdwn
+++ b/doc/design/roadmap.mdwn
@@ -1,5 +1,6 @@
 ## ahead
 
+* [[design/caching_database]] for metadata views, direct mode mappings
 * [[assistant/deltas]]
 * [[assistant/gpgkeys]]
 * [[assistant/telehash]]
@@ -8,7 +9,7 @@
 
 ## now
 
-* Feb 2015 user-driven features and polishing, [[design/caching_database]]
+* Feb 2015 user-driven features and polishing, [[design/caching_database]] part 1
 
 ## the rearview
 
diff --git a/doc/devblog/day_257__release_day.mdwn b/doc/devblog/day_257__release_day.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_257__release_day.mdwn
@@ -0,0 +1,17 @@
+Today's release doesn't have the database branch merged of course, but it
+still has a significant amount of changes.
+
+Developed a test case for the sqlite problem, that
+reliably reproduces it, and sent it to the sqlite mailing list. It seems
+that under heavy write load, when a new connection is made to the database,
+SELECT can fail for a little while. Once one SELECT succeeds, that database
+connection becomes solid, and won't fail any more (apparently). This makes
+me think there might be some connection initialization steps that don't end
+up finishing before the SELECT goes through in this situation. I should be
+able to work around this problem by probing new connections for stability,
+and probably will have to, since it'll be years before any bug fixed sqlite
+is available everywhere.
+
+I also noticed that current git-annex incremental parallel fsck doesn't
+really parallelize well; eg the processes do duplicate work. So, the
+database branch is not really a regression in this area.
diff --git a/doc/devblog/day_258__database_branch_merged.mdwn b/doc/devblog/day_258__database_branch_merged.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_258__database_branch_merged.mdwn
@@ -0,0 +1,25 @@
+I'm snowed in, but keeping busy..
+
+Developed a complete workaround for the [sqlite SELECT ErrorBusy bug](http://news.gmane.org/find-root.php?message_id=20150219163255.GA13383%40kitenet.net).
+So after a week, I finally have sqlite working robustly. And, I merged in
+the branch that uses sqlite for incremental fsck.
+
+Benchmarking an incremental fsck --fast run, checking 40 thousand files,
+it used to take 4m30s using sticky bits, and using sqlite slowed it down by
+10s. So one added second per 4 thousand or so files. I think that's ok.
+Incremental fsck is intended to be used in big repos, which are probably not
+checked in --fast most, so the checksumming of files will by far swamp
+that overhead.
+
+Also got sqlite and persistent installed on all the autobuilders. This
+was easier than expected, because persistent bundles its own copy of
+sqlite.
+
+That would have been a good stopping place for the day's work.. But then I
+got to spent 5 more hours getting the EvilSplicer to support Persistent.
+Urgh. :-/
+
+Now I can look forward to using sqlite for something more interesting than
+incremental fsck, like metadata caching for views, or the direct mode mappings.
+But, given all the trouble I had with sqlite, I'm going to put that off for
+a little while, to make sure that I've really gotten sqlite to work robustly.
diff --git a/doc/devblog/day_259__submodules.mdwn b/doc/devblog/day_259__submodules.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_259__submodules.mdwn
@@ -0,0 +1,8 @@
+I had thought that git-annex and git submodules couldn't mix. However,
+looking at it again, it turned out to be possible to use git-annex quite
+sanely in a submodule, with just a little tweaking of how git normally
+configures the repository. Details of this still experimental feature are in
+[[/submodules]].
+
+There is still some work to be done to make git-annex work with submodules
+in repositories on filesystems that don't support symlinks.
diff --git a/doc/devblog/day_260__random_month.mdwn b/doc/devblog/day_260__random_month.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_260__random_month.mdwn
@@ -0,0 +1,27 @@
+This month is going to be a bit more random than usual where git-annex
+development is concerned.
+
+* On Saturday, the [Seven Day Roguelike](http://7drl.org/) competition
+  begins, and I will be spending a week building a game in haskell,
+  to the exclusion of almost all other work.
+* On March 18th, I'll be at the [Boston Haskell User's group](http://www.meetup.com/Boston-Haskell/events/219298257/).
+  (Attending, not presenting.)
+* March 19-20, I'll be at Dartmouth visiting with the DataLad developers
+  and learning more about what it needs from git-annex.
+* March 21-22, I'll be at the FSF's [LibrePlanet](https://libreplanet.org/2015)
+  conference at MIT.
+
+Got started on the randomness today with this 
+[[design proposal for using git-annex to back up the entire Internet Archive|design/iabackup]].
+This is something the Archive Team is [considering taking on](http://archiveteam.org/index.php?title=INTERNETARCHIVE.BAK),
+and I had several hours driving and hiking to think about it and came up
+with a workable design. (Assuming large enough crowd of volunteers.)
+
+Don't know if it will happen, but it was a useful thought problem to see how
+git-annex works, and doesn't work in this unusual use case.
+
+One interesting thing to come out of that is that git-annex fsck does not
+currently make any record of successful fscks. In a very large distributed
+system, it can be useful to have successful fscks of an object's content recorded,
+by updating the timestamp in the location log to say "this repository still
+had the content at this time".
diff --git a/doc/devblog/day_261__random_improvements.mdwn b/doc/devblog/day_261__random_improvements.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_261__random_improvements.mdwn
@@ -0,0 +1,5 @@
+Fixed a mojibake bug that affected metadata values that included both
+whitespace and unicode characters. This was very fiddly to get right.
+
+Finished up Monday's work to support submodules, getting them working
+on filesystems that don't support symlinks.
diff --git a/doc/devblog/day_262__ipfs.mdwn b/doc/devblog/day_262__ipfs.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_262__ipfs.mdwn
@@ -0,0 +1,16 @@
+Did a deep dive into [ipfs](http://ipfs.io/) last night. It has great
+promise.
+
+As a first step toward using it with git-annex, I built an experimental
+[[ipfs_special_remote|special_remotes/ipfs]]. It has some nice abilities;
+any ipfs address can be downloaded to a file in the repository:
+
+	git annex addurl ipfs:QmYgXEfjsLbPvVKrrD4Hf6QvXYRPRjH5XFGajDqtxBnD4W --file somefile
+
+And, any file in the git-annex repository can be published to the world
+via ipfs, by simply using `git annex copy --to ipfs`. The ipfs address
+for the file is then visible in `git annex whereis`.
+
+Had to extend the external special remote protocol slightly for that, so
+that ipfs addresses can be recorded as uris in git-annex, and will show up
+in `git annex whereis`.
diff --git a/doc/devblog/day_263__diving_back_in.mdwn b/doc/devblog/day_263__diving_back_in.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_263__diving_back_in.mdwn
@@ -0,0 +1,7 @@
+After an intense week away, I didn't mean to work on git-annex today, but I
+got sucked back in..
+
+Worked on some plumbing commands for mass repository creation.
+Made `fromkey` be able to read a stream of files to create from stdin.
+Added a new `registerurl` plumbing command, that reads a stream of keys and
+urls from stdin.
diff --git a/doc/devblog/day_264__catching_up.mdwn b/doc/devblog/day_264__catching_up.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/devblog/day_264__catching_up.mdwn
@@ -0,0 +1,7 @@
+Caught up with most of the recent backlog today. Was not very bad.
+
+Fixed `remotedaemon` to support gcrypt remotes, which was never
+quite working before.
+
+Seem to be on track to making a release tomorrow with a whole month's
+changes.
diff --git a/doc/encryption/comment_1_1afca8d7182075d46db41f6ad3dd5911._comment b/doc/encryption/comment_1_1afca8d7182075d46db41f6ad3dd5911._comment
deleted file mode 100644
--- a/doc/encryption/comment_1_1afca8d7182075d46db41f6ad3dd5911._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="zooko"
- ip="75.220.153.232"
- subject="Tahoe-LAFS comes with encryption"
- date="2011-05-18T04:32:14Z"
- content="""
-The Tahoe-LAFS special remote automatically encrypts and adds cryptography integrity checks/digital signatures. For that special remote you should not use the git-annex encryption scheme.
-
-Tahoe-LAFS encryption generates a new independent key for each file. This means that you can share access to one of the files without thereby sharing access to all of them, and it means that individual files can be deduplicated among multiple users.
-"""]]
diff --git a/doc/encryption/comment_1_4257e3c4ae559f1c0595a903f738fd7e._comment b/doc/encryption/comment_1_4257e3c4ae559f1c0595a903f738fd7e._comment
new file mode 100644
--- /dev/null
+++ b/doc/encryption/comment_1_4257e3c4ae559f1c0595a903f738fd7e._comment
@@ -0,0 +1,28 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawlZ-6dtxJY4cP7shhvV8E6YyuV0Rak8it4"
+ nickname="Giovanni"
+ subject="comment 1"
+ date="2015-03-10T22:16:09Z"
+ content="""
+I have a gcrypt special remote encrypted in hybrid mode, when I try to add a keyid using:
+
+     git annex enableremote myremote keyid+=XXXXXXXX
+
+I get this error:
+
+     enableremote myremote (encryption update) (hybrid cipher with gpg keys XXXXXXXX XXXXXXX) fatal: remote myremote already exists. 
+     git-annex: git [Params \"remote add\",Param \"myremote\",Param \"gcrypt::XXXXXXXXXXX:gcrypt-tests\"] failed
+
+this is my git-annex version info: 
+
+     git-annex version: 5.20141125 
+     build flags: Assistant Webapp Webapp-secure Pairing Testsuite S3 WebDAV Inotify DBus DesktopNotify XMPP 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 ddar hook external 
+     local repository version: 5 
+     supported repository version: 5 
+     upgrade supported from repository versions: 0 1 2 4
+
+am I doing something wrong? thank you Giovanni
+
+"""]]
diff --git a/doc/forum/4hr+_sync_on_new_remote___40__USB_drive__41__.mdwn b/doc/forum/4hr+_sync_on_new_remote___40__USB_drive__41__.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/4hr+_sync_on_new_remote___40__USB_drive__41__.mdwn
@@ -0,0 +1,92 @@
+I need some help understanding what would cause ``git-annex sync`` to still be running 4hrs+ on a new remote (FAT32 USB drive - BTEST) ? From all my searching, it appears to be part of git's optimization routines. But to be this long and slow seems odd. Also I am not sure what there would be optimize since it's a brand new remote ? The src (WTEST) doesn't seem to show any need to run ``git gc``.
+
+I followed the walkthrough's setup of a remote and followed that up with ``git-annex sync``. I did not specify the source for the sync as there is only one other (WTEST). The content is mostly ISO files and Win32 executables in 7 separate commits. In between ``git-annex import`` and ``git commit``, the working directory was removed with ``git rm '*'`` but no ``git-annex drop``. There were lots of duplicate files and it truly was satisfying to not see the disk usage increase. My backend is also MD5E for purposes of quicker imports and ease of hash lookup from other sources.
+
+I would like to have 20-30 USB remotes. The length of time to get one remote up and running at this point is horrendous. Other people seem to have better experiences with it. Only odd thing that I see with my configuration is that the remote FAT32 drive is in ``indirect`` mode. My understanding is that ``git-annex`` would automatically switch to ``direct`` if it detected a filesystem that did not support symbolic links. 
+
+What is wrong with my setup ? How can I fix it ?
+
+Here's the basic config of WTEST.
+
+[[!format sh """
+
+WTEST$ git-annex info
+
+repository mode: indirect
+trusted repositories: 0
+semitrusted repositories: 4
+        00000000-0000-0000-0000-000000000001 -- web
+        00000000-0000-0000-0000-000000000002 -- bittorrent
+        98dfasdf-ab83-4a0e-8b73-4dfasffdsaff1ae -- WTEST [here]
+        9dfdsfdf8-c5d5-4761-ab67-ffsadfsadfsa83 -- BTEST
+untrusted repositories: 0
+transfers in progress: none
+available local disk space: 488.16 gigabytes (+1 megabyte reserved)
+local annex keys: 57327
+local annex size: 58.57 gigabytes
+annexed files in working tree: 4322
+size of annexed files in working tree: 6.82 gigabytes
+bloom filter size: 16 mebibytes (11.5% full)
+backend usage:
+        MD5E: 61649
+"""]]
+
+[[!format sh """
+WTEST$git object-count -v
+
+count: 521829
+size: 66794240
+in-pack: 0
+packs: 0
+size-pack: 0
+prune-packable: 0
+garbage: 0
+size-garbage: 0
+"""]]
+
+
+[[!format sh """
+WTEST$git config -l
+
+core.repositoryformatversion=0
+core.filemode=false
+core.bare=false
+core.logallrefupdates=true
+core.ignorecase=true
+core.precomposeunicode=true
+annex.uuid=98dfasdf-ab83-4a0e-8b73-4dfasffdsaff1ae
+annex.sshcaching=false
+annex.version=5
+annex.backends=MD5E
+annex.queuesize=102400
+annex.genmetadata=true
+remote.BTEST.url=/Volumes/BTEST
+remote.BTEST.fetch=+refs/heads/*:refs/remotes/BTEST/*
+remote.BTEST.annex-uuid=9dfdsfdf8-c5d5-4761-ab67-ffsadfsadfsa83
+"""]]
+
+**The long running sync.**
+
+[[!format sh """ 
+BTEST$ git-annex sync
+
+commit  ok
+
+pull origin
+
+Auto packing the repository for optimum performance. You may also
+
+run "git gc" manually. See "git help gc" for more information.
+
+Counting objects: 521834, done.
+
+Delta compression using up to 4 threads.
+
+Compressing objects:  12% (59687/462488)
+"""]]
+
+**Update 7hrs later:**
+
+[[!format sh """
+Writing objects:  70% (366184/521834)
+"""]]
diff --git a/doc/forum/Do_I_have_naming_ssh_remote_issue__63__.mdwn b/doc/forum/Do_I_have_naming_ssh_remote_issue__63__.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/Do_I_have_naming_ssh_remote_issue__63__.mdwn
@@ -0,0 +1,45 @@
+I'm running [git-annex](http://ix.io/gJJ) from <https://aur.archlinux.org/packages/git-annex-bin> btw on Archlinux.
+
+I fetched a copy of my [git-annex wedding test repo](https://github.com/kaihendry/krwedding) to a machine on ssh called 'bible'.
+
+Now I'm trying to fetch via ssh from my local machine "X1C3".
+
+I can't work out how to fetch from it from b1b15a9b-1aa1-4f94-8b9a-2186d71c0d1a .... what am I missing?
+
+    X1C3:~/annex/krwedding$ git-annex whereis krfeature.mp4
+     whereis krfeature.mp4 (3 copies)
+        00000000-0000-0000-0000-000000000001 -- web
+        10418340-834d-41c2-b38f-7ee84bf6a23a -- s3
+        b1b15a9b-1aa1-4f94-8b9a-2186d71c0d1a -- Jamie's bible
+      web: http://r2d2.webconverger.org/2013-12-22/krfeature.mp4
+      web: http://static.prazefarm.co.uk/krfeature.mp4
+      web: https://objects.dreamhost.com/wedding-video/krfeature.mp4
+    ok
+    X1C3:~/annex/krwedding$ git-annex get . --from "Jamie's bible"
+    git-annex: there is no available git remote named "Jamie's bible"
+    X1C3:~/annex/krwedding$ git-annex enableremote Jamie's bible
+    > ^C
+    X1C3:~/annex/krwedding$ git-annex enableremote "Jamie's bible"
+    git-annex: Unknown special remote name.
+    Known special remotes: s3
+    X1C3:~/annex/krwedding$ git-annex get . --from b1b15a9b-1aa1-4f94-8b9a-2186d71c0d1a
+    git-annex: there is no available git remote named "b1b15a9b-1aa1-4f94-8b9a-2186d71c0d1a"
+
+Why doesn't the UUID work? :/
+
+I even [tried renaming the remote to the UUID... didn't work](http://ix.io/gJI)
+
+**Solution**: Neither UUID or the description is used by get. I also should not have resorted to [[special_remotes]] setup for setting up a git remote.
+
+# Issue 1
+
+Keep getting `git-annex-shell: user error (git ["config","--null","--list"] exited 126)` even though when I run `git config` my return error is 0: <http://ix.io/gJG>
+
+**Solution**: This was because my ssh git URL was incorrect. A better error message has been implemented: <http://source.git-annex.branchable.com/?p=source.git;a=commitdiff;h=3439ea4>
+
+
+# Issue 2
+
+I can't work out the [git-annex remote type for ssh, in order to rename the remote](http://ix.io/gJH). I think the issue here is that my ssh remote name "Jamie's bible" doesn't match with the `git remote` name bible.
+
+**Solution**: A _rw_ git URL configured with `git remote` are not [[special_remotes]]. I confused the two. If you need to define public git URL ([[time capsule use case|future_proofing]]), it is possible with an undocumented `git annex initremote foo type=git location=url`. So to summarise, just manually setup the git remote `git remote add ssh://someplace/path/to/repo` (don't worry about the name) and git-annex will find it!
diff --git a/doc/forum/NTFS_usb_on_linux_unable_to_connect_to_ssh_remote.mdwn b/doc/forum/NTFS_usb_on_linux_unable_to_connect_to_ssh_remote.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/NTFS_usb_on_linux_unable_to_connect_to_ssh_remote.mdwn
@@ -0,0 +1,29 @@
+There are SSH keys in ~/.ssh to a remote server that I added as a git annex remote. On my Debian box, I am able to `git annex copy` and `git annex move` to and from the remote to a local repo at `~/archive` with no problems. I also have no problems with external USB drives formatted ext4. 
+
+I have an external usb drive formatted NTFS that I connect to a Debian box. I added the remote server like the others and when I try to copy or move to and from it, this error code shows up. 
+
+
+
+    pull archive 
+    Control socket connect(.git/annex/ssh/f7be67fcc0a6f016ba90edcdd8e02e1f): Connection refused
+    Failed to connect to new control master
+    fatal: Could not read from remote repository.
+
+    Please make sure you have the correct access rights
+    and the repository exists.
+    failed
+    push archive 
+    Control socket connect(.git/annex/ssh/f7be67fcc0a6f016ba90edcdd8e02e1f): Connection refused
+    Failed to connect to new control master
+    fatal: Could not read from remote repository.
+
+    Please make sure you have the correct access rights
+    and the repository exists.
+
+    Pushing to archive failed.
+
+
+
+I think it is because of NTFS and the ssh key stored in `~/.ssh`, but I don't know what is going on. 
+
+Thanks!
diff --git a/doc/forum/Newbie_question_for_a_simple_task.mdwn b/doc/forum/Newbie_question_for_a_simple_task.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/Newbie_question_for_a_simple_task.mdwn
@@ -0,0 +1,11 @@
+Hi,
+
+I am pretty confident, that this is a newbie question. Nevertheless, I did not find the answer (or the solution) event after looking at the screencasts and reading through the files.
+
+I want to sync 2 clients on different networks though a ssh cloud server begin a full backup.
+Also, I would like to do this for 2 different folders on the clients and server.
+I mean : client 1, 2 and the server sync a repo named "DATA" and also sync another repo named "IMAGES"
+
+Setting the client1 as local client repo and also ssh remote repo works quite well, it uploads everything to the server. Then I make the same on the second client, and it does not start to download everything from the server...
+
+Any clue ?
diff --git a/doc/forum/Per_directory_numcopies.mdwn b/doc/forum/Per_directory_numcopies.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/Per_directory_numcopies.mdwn
@@ -0,0 +1,5 @@
+I have some photo backups that I would like to have 2 copies but the rest can be one. 
+
+Is there any way to create numcopies rules per directory, rather than by filetype?
+
+I really enjoy this program Joey, thanks!
diff --git a/doc/forum/Repository_backup.mdwn b/doc/forum/Repository_backup.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/Repository_backup.mdwn
@@ -0,0 +1,5 @@
+What's the best way of backing up the git repository itself? I feel fairly comfortable using a special remote to create an offsite backup in S3 or Glacier or whatnot, but restoring from those still requires I have a working repository somewhere that can map chunks back to files, no? 
+
+I can probably just create a repo that has no content, tar it up, and store it on my backup medium (or on bitbucket or wherever), but that seems kinda hackish--it'd be nice to handle this within git-annex. In fact, it'd be really neat if I could handle this with any existing special remote--for example, if there were a way to commit and restore the git repo state (and symlink tree) to the remote. But that doesn't seem to exist. Is there a recommended approach for this? Am I just missing something obvious?
+
+Thanks. 
diff --git a/doc/forum/Verification.mdwn b/doc/forum/Verification.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/Verification.mdwn
@@ -0,0 +1,9 @@
+Hi,
+
+I have a simple Client Mac <> FullBackup on remote SSH <> Client On Mac setup which seems to work great.
+
+I have 2 questions :
+- Whenever a new file is created or changed it can takes a few hours until the second client gets the file. Is this normal ?
+- How Can I make sure, that all the files are on the FullBackup ?
+
+Many thank !
diff --git a/doc/forum/Verification/comment_1_d56818a8f5b3a94ecf5159c76f24768c._comment b/doc/forum/Verification/comment_1_d56818a8f5b3a94ecf5159c76f24768c._comment
new file mode 100644
--- /dev/null
+++ b/doc/forum/Verification/comment_1_d56818a8f5b3a94ecf5159c76f24768c._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2015-02-27T18:51:52Z"
+ content="""
+Well, it depends on how big the files are, but taking a few hours to sync
+might indicate that your repositories are not immediately notifying
+one-another of changes. It might be falling back to polling every half
+an hour for new changes.
+
+You could fix that by setting up XMPP, or better, by installing git-annex
+5.20140421 or newer on the SSH server; then the clients would immediately
+notify when there are changes.
+
+You can find out if all files are present on the server by running
+`git annex find --not --in $server` on one of the clients. Any files
+it prints out have not been stored in the server.
+"""]]
diff --git a/doc/forum/Verification/comment_2_7df45d1e20a32458791603d5b9fe3dc4._comment b/doc/forum/Verification/comment_2_7df45d1e20a32458791603d5b9fe3dc4._comment
new file mode 100644
--- /dev/null
+++ b/doc/forum/Verification/comment_2_7df45d1e20a32458791603d5b9fe3dc4._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="Régis"
+ subject="comment 2"
+ date="2015-02-27T21:38:05Z"
+ content="""
+Thanks for this speedy answer !
+
+I have version 5.20150219 installed on all the clients and on the server.
+The ssh server is a gcrypt repository. Could this be the reason of the clients not being notificated of the  changes ??
+
+Also, in theory, some file on one of the repositories could get corrupted, deleted, whatever. How can I make the repo check if everything is like intended on the other repos ? 
+For example, I made a test renaming a file within the objects directory on the remote ssh server and ran git annex fchk, but it reported nothing...
+
+Many thanks again !
+"""]]
diff --git a/doc/forum/Verification/comment_3_74db3ec8b03f48912306e48b8d5f7242._comment b/doc/forum/Verification/comment_3_74db3ec8b03f48912306e48b8d5f7242._comment
new file mode 100644
--- /dev/null
+++ b/doc/forum/Verification/comment_3_74db3ec8b03f48912306e48b8d5f7242._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Régis"
+ subject="comment 3"
+ date="2015-02-28T18:33:27Z"
+ content="""
+Also, I noted a difference between encrypted (gcrypt) repos and unencrypted repos. The second ones have the other icon saying that it is live messaging. The encrypted one have a standard icon.
+Is it a technical limitation that encrypted repos can not live message ? And could it be the reason why the sync is not happening itself until i manually choose \"sync\" from the menu ?
+"""]]
diff --git a/doc/forum/Verification/comment_4_eb4d936a9bd577f58483b278ae5dc5f6._comment b/doc/forum/Verification/comment_4_eb4d936a9bd577f58483b278ae5dc5f6._comment
new file mode 100644
--- /dev/null
+++ b/doc/forum/Verification/comment_4_eb4d936a9bd577f58483b278ae5dc5f6._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2015-03-16T18:36:45Z"
+ content="""
+You can use `git annex fsck` to verify your repository contents.
+If you want to verify a local repository, the best thing to do is
+to run `git annex fsck` there. If you cannot do that, you can use
+`git annex fsck --from remoterepo --fast` to verify a remote. If you leave
+off the --fast it will download all file contents to completely verify
+them.
+
+I suggest you read git-annex's documentation, there is plenty of it about
+using git-annex fsck to verify repositories.
+"""]]
diff --git a/doc/forum/Verification/comment_5_c327c72ceced27920681d5f93bc256c8._comment b/doc/forum/Verification/comment_5_c327c72ceced27920681d5f93bc256c8._comment
new file mode 100644
--- /dev/null
+++ b/doc/forum/Verification/comment_5_c327c72ceced27920681d5f93bc256c8._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2015-03-16T18:39:01Z"
+ content="""
+The lack of "live messaging" for gcrypt repos is a bug. I'm fixing
+it now and the next version of git-annex will have remotedaemon
+properly supporting gcrypt repos.
+"""]]
diff --git a/doc/forum/View_special_remote_information__63__.mdwn b/doc/forum/View_special_remote_information__63__.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/View_special_remote_information__63__.mdwn
@@ -0,0 +1,1 @@
+How is it possible to view the URL etc of a special remote with git annex? I checked out a git annex repository and would like to know where the files where fetched from. 
diff --git a/doc/forum/Where_are_my_remote_ssh_files__63__.mdwn b/doc/forum/Where_are_my_remote_ssh_files__63__.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/Where_are_my_remote_ssh_files__63__.mdwn
@@ -0,0 +1,10 @@
+<img src=http://s.natalian.org/2015-03-10/where-are-the-files.png>
+
+I managed to sync files to a remote ssh store "bible" with `git annex sync --content` however, where I ssh to bible, I was surprised not to see any of the JPG files that were copied there.
+
+
+What am I missing?
+
+# Solution
+
+I need to run `git annex sync` on the host bible too!
diff --git a/doc/forum/git_annex_add_freezes_on_direct_repo.mdwn b/doc/forum/git_annex_add_freezes_on_direct_repo.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/git_annex_add_freezes_on_direct_repo.mdwn
@@ -0,0 +1,21 @@
+I've found that running git annex add on a directory in a direct repository freezes. Example output:
+
+    > git annex add Signs\ \(2002\ Film\) --debug
+    
+    [2015-02-22 10:10:04 GMT] read: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","ls-files","--others","--exclude-standard","-z","--","Signs (2002 Film)"]
+    [2015-02-22 10:10:04 GMT] chat: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","cat-file","--batch"]
+    add Signs (2002 Film)/VIDEO_TS/VIDEO_TS.BUP [2015-02-22 10:10:04 GMT] chat: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","check-attr","-z","--stdin","annex.backend","annex.numcopies","--"]
+    [2015-02-22 10:10:05 GMT] chat: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","hash-object","-t","blob","-w","--stdin","--no-filters"]
+    [2015-02-22 10:10:05 GMT] chat: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","cat-file","--batch"]
+    ok
+    add Signs (2002 Film)/VIDEO_TS/VIDEO_TS.IFO [2015-02-22 10:10:05 GMT] chat: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","hash-object","-t","blob","-w","--stdin","--no-filters"]
+    ok
+
+Lots of files, ending in:
+
+    add Signs (2002 Film)/VIDEO_TS/VTS_13_1.VOB [2015-02-22 10:56:49 GMT] chat: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","hash-object","-t","blob","-w","--stdin","--no-filters"]
+    ok
+    [2015-02-22 10:56:49 GMT] read: git ["--git-dir=/Volumes/plato/Films/.git","--work-tree=/Volumes/plato/Films","-c","core.bare=false","ls-files","--modified","-z","--","Signs (2002 Film)"]
+
+
+It then hung for just under two hours before I hit ctrl+C. The files are on a remote SMB server mounted via OS X (hence direct mode) and git annex is being run on an OS X machine. git version 2.3.0, git-annex version 5.20150205. Both installed using homebrew. Any thoughts?
diff --git a/doc/forum/noob_question._VPS_web_assistant.mdwn b/doc/forum/noob_question._VPS_web_assistant.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/forum/noob_question._VPS_web_assistant.mdwn
@@ -0,0 +1,7 @@
+Hi
+
+So I've installed git-annex on my Debian VPS.
+
+How do I find out the URL to access the web UI / assistant?
+
+Thanks!
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -236,6 +236,10 @@
   Urls to torrent files (including magnet links) will cause the content of
   the torrent to be downloaded, using `aria2c`.
 
+  To prevent special handling of urls by quvi, bittorrent, and other
+  special remotes, specify `--raw`. This will for example, make addurl
+  download the .torrent file and not the contents it points to.
+
 * `rmurl file url`
 
   Record that the file is no longer available at the url.
@@ -289,7 +293,8 @@
   The default template is '${feedtitle}/${itemtitle}${extension}'
   (Other available variables: feedauthor, itemauthor, itemsummary, itemdescription, itemrights, itemid, itempubdate, title, author)
 
-  The `--relaxed` and `--fast` options behave the same as they do in addurl.
+  The `--relaxed`, `--fast`, and `--raw` options behave the same as they
+  do in addurl.
 
   When quvi is installed, links in the feed are tested to see if they
   are on a video hosting site, and the video is downloaded. This allows
@@ -699,7 +704,7 @@
 
 * `whereis [path ...]`
 
-  Displays a information about where the contents of files are located.
+  Displays information about where the contents of files are located.
 
 * `list [path ...]`
 
@@ -947,11 +952,29 @@
 
         	git annex examinekey --format='.git/annex/objects/${hashdirmixed}${key}/${key}'
 
-* `fromkey key file`
+* `fromkey [key file]`
 
   This plumbing-level command can be used to manually set up a file
   in the git repository to link to a specified key.
 
+  Normally, the annex needs to already contain the content object for the
+  key. To override this, use --force.
+
+  If the key and file are not specified on the command line, they are
+  instead read from stdin. Any number of lines can be provided in this
+  mode, each containing a key and filename, sepearated by whitespace.
+
+* `registerurl [key url]`
+
+  This plumbing-level command can be used to register urls where a
+  key can be downloaded from.
+
+  No verification is performed of the url's contents.
+
+  If the key and url are not specified on the command line, they are
+  instead read from stdin. Any number of lines can be provided in this
+  mode, each containing a key and url, sepearated by whitespace.
+
 * `dropkey [key ...]`
 
   This plumbing-level command drops the annexed data for the specified
@@ -1392,9 +1415,12 @@
 
 When a repository is in one of the standard predefined groups, like "backup"
 and "client", setting its preferred content to "standard" will use a
-built-in preferred content expression developed for that group. Or,
-setting its preferred content to "groupwanted" will make it use whatever
-groupwanted expression you set for the group.
+built-in preferred content expression developed for that group. 
+See <https://git-annex.branchable.com/preferred_content/standard_groups/>
+
+If you have set a groupwanted expression for a group, it will be used
+when a repository in the group has its preferred content set to
+"groupwanted".
 
 # SCHEDULED JOBS
 
diff --git a/doc/install.mdwn b/doc/install.mdwn
--- a/doc/install.mdwn
+++ b/doc/install.mdwn
@@ -9,7 +9,7 @@
 &nbsp;&nbsp;[[Debian]]            | `apt-get install git-annex`
 &nbsp;&nbsp;[[Ubuntu]]            | `apt-get install git-annex`
 &nbsp;&nbsp;[[Fedora]]            | `yum install git-annex`
-&nbsp;&nbsp;[[FreeBSD]]           | `pkg_add -r hs-git-annex`
+&nbsp;&nbsp;[[FreeBSD]]           | `pkg install hs-git-annex`
 &nbsp;&nbsp;[[ArchLinux]]         | `yaourt -Sy git-annex-bin`
 &nbsp;&nbsp;[[NixOS]]             | `nix-env -i git-annex`
 &nbsp;&nbsp;[[Gentoo]]            | `emerge git-annex`
diff --git a/doc/install/Linux_standalone.mdwn b/doc/install/Linux_standalone.mdwn
--- a/doc/install/Linux_standalone.mdwn
+++ b/doc/install/Linux_standalone.mdwn
@@ -32,3 +32,7 @@
 * x86-32: [download tarball](https://downloads.kitenet.net/git-annex/autobuild/i386/git-annex-standalone-i386.tar.gz) ([build logs](https://downloads.kitenet.net/git-annex/autobuild/i386/))
 * x86-64: [download tarball](https://downloads.kitenet.net/git-annex/autobuild/amd64/git-annex-standalone-amd64.tar.gz) ([build logs](https://downloads.kitenet.net/git-annex/autobuild/amd64/))
 * arm: [download tarball](https://downloads.kitenet.net/git-annex/autobuild/armel/git-annex-standalone-armel.tar.gz) ([build logs](https://downloads.kitenet.net/git-annex/autobuild/armel/))
+
+## technical details
+
+The way those tarballs are built is described in [joeyh's blog](http://joeyh.name/blog/entry/completely_linux_distribution-independent_packaging/).
diff --git a/doc/install/OSX/comment_10_e5172de344908f85ce6cf976e3c3806b._comment b/doc/install/OSX/comment_10_e5172de344908f85ce6cf976e3c3806b._comment
new file mode 100644
--- /dev/null
+++ b/doc/install/OSX/comment_10_e5172de344908f85ce6cf976e3c3806b._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawk7iPiqWr3BVPLWEDvJhSSvcOqheLEbLNo"
+ nickname="Dirk"
+ subject="Is the Mavericks build still beeing updated?"
+ date="2015-02-26T12:22:51Z"
+ content="""
+I am still using Mac OS 10.9. Recently downloading a new git-annex version showed that the Mavericks build is still based on 5.20141104, while the Yosemite is 5.20150219. I am wondering if this is a misstake or if it is time for me to move on to Yosemite? ;-)
+
+
+"""]]
diff --git a/doc/install/OSX/comment_11_8d53c477b441ab0984257b21003c7cc7._comment b/doc/install/OSX/comment_11_8d53c477b441ab0984257b21003c7cc7._comment
new file mode 100644
--- /dev/null
+++ b/doc/install/OSX/comment_11_8d53c477b441ab0984257b21003c7cc7._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""Re: Is the Mavericks build still beeing updated?"""
+ date="2015-02-27T18:57:51Z"
+ content="""
+The Yosemite build linked above has been reported to work on Mavericks too,
+and is being updated. There is no separate Mavericks build anymore.
+
+There were some old mavericks builds floating around the downloads site; 
+I've removed those and symlinked the mavericks directory to the yosimite
+directory.
+"""]]
diff --git a/doc/install/fromsource.mdwn b/doc/install/fromsource.mdwn
--- a/doc/install/fromsource.mdwn
+++ b/doc/install/fromsource.mdwn
@@ -36,9 +36,9 @@
 
 ## minimal build with cabal
 
-This can be done anywhere, and builds git-annex without some features that
-require C libraries, that can be harder to get installed. This is plenty to
-get started using it, although it does not include the assistant or webapp.
+This can be done anywhere, and builds git-annex without some optional features
+that require harder-to-install C libraries. This is plenty to let you get started with
+git-annex, but it does not include the assistant or webapp.
 
 Inside the source tree, run:
 
diff --git a/doc/links/the_details.mdwn b/doc/links/the_details.mdwn
--- a/doc/links/the_details.mdwn
+++ b/doc/links/the_details.mdwn
@@ -3,6 +3,7 @@
 * [[encryption]]
 * [[key-value backends|backends]]
 * [[bare_repositories]]
+* [[submodules]]
 * [[internals]]
 * [[scalability]]
 * [[design]]
diff --git a/doc/news/version_5.20141231.mdwn b/doc/news/version_5.20141231.mdwn
deleted file mode 100644
--- a/doc/news/version_5.20141231.mdwn
+++ /dev/null
@@ -1,14 +0,0 @@
-git-annex 5.20141231 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * vicfg: Avoid crashing on badly encoded config data.
-   * Work around statfs() overflow on some XFS systems.
-   * sync: Now supports remote groups, the same way git remote update does.
-   * setpresentkey: A new plumbing-level command.
-   * Run shutdown cleanup actions even if there were failures processing
-     the command. Among other fixes, this means that addurl will stage
-     added files even if adding one of the urls fails.
-   * bittorrent: Fix locking problem when using addurl file://
-   * Windows: Fix local rsync filepath munging (fixes 26 test suite failures).
-   * Windows: Got the rsync special remote working.
-   * Windows: Fix handling of views of filenames containing '%'
-   * OSX: Switched away from deprecated statfs64 interface."""]]
diff --git a/doc/news/version_5.20150317.mdwn b/doc/news/version_5.20150317.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/news/version_5.20150317.mdwn
@@ -0,0 +1,42 @@
+git-annex 5.20150317 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * fsck: Incremental fsck uses sqlite to store its records, instead
+     of abusing the sticky bit. Existing sticky bits are ignored;
+     incremental fscks started by old versions won't be resumed by
+     this version.
+   * fsck: Multiple incremental fscks of different repos (including remotes)
+     can now be running at the same time in the same repo without it
+     getting confused about which files have been checked for which remotes.
+   * unannex: Refuse to unannex when repo is too new to have a HEAD,
+     since in this case there must be staged changes in the index
+     (if there is anything to unannex), and the unannex code path
+     needs to run with a clean index.
+   * Linux standalone: Set LOCPATH=/dev/null to work around
+     https://ghc.haskell.org/trac/ghc/ticket/7695
+     This prevents localization from working, but git-annex
+     is not localized anyway.
+   * sync: As well as the synced/git-annex push, attempt a
+     git-annex:git-annex push, as long as the remote branch
+     is an ancestor of the local branch, to better support bare git repos.
+     (This used to be done, but it forgot to do it since version 4.20130909.)
+   * When re-execing git-annex, use current program location, rather than
+     ~/.config/git-annex/program, when possible.
+   * Submodules are now supported by git-annex!
+   * metadata: Fix encoding problem that led to mojibake when storing
+     metadata strings that contained both unicode characters and a space
+     (or '!') character.
+   * Also potentially fixes encoding problem when embedding credentials
+     that contain unicode characters.
+   * sync: Fix committing when in a direct mode repo that has no HEAD ref.
+     (For example, a newly checked out git submodule.)
+   * Added SETURIPRESENT and SETURIMISSING to external special remote protocol,
+     useful for things like ipfs that don't use regular urls.
+   * addurl: Added --raw option, which bypasses special handling of quvi,
+     bittorrent etc urls.
+   * git-annex-shell: Improve error message when the specified repository
+     doesn't exist or git config fails for some reason.
+   * fromkey --force: Skip test that the key has its content in the annex.
+   * fromkey: Add stdin mode.
+   * registerurl: New plumbing command for mass-adding urls to keys.
+   * remotedaemon: Fixed support for notifications of changes to gcrypt
+     remotes, which was never tested and didn't quite work before."""]]
diff --git a/doc/preferred_content.mdwn b/doc/preferred_content.mdwn
--- a/doc/preferred_content.mdwn
+++ b/doc/preferred_content.mdwn
@@ -179,11 +179,6 @@
 
 So when is `unused` useful in a preferred content expression?
 
-Using `git annex sync --content --all` will ensure that all keys, including
-unused ones, are examined and the preferred content expressions followed.
-Similarly, `git annex sync --content --unused` will only look at the unused
-keys.
-
 The git-annex assistant periodically scans for unused files, and
 moves them to some repository whose preferred content expression
 matches "unused". (Or, if annex.expireunused is set, it may just delete
diff --git a/doc/required_content/comment_1_b9576aaa31258e9bdf18a4eac8d61bfb._comment b/doc/required_content/comment_1_b9576aaa31258e9bdf18a4eac8d61bfb._comment
new file mode 100644
--- /dev/null
+++ b/doc/required_content/comment_1_b9576aaa31258e9bdf18a4eac8d61bfb._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawnG-DZQa3d3Jn7K2q36TlbmZ8v2YuV-23M"
+ nickname="Fer"
+ subject="Command line?"
+ date="2015-03-17T13:31:34Z"
+ content="""
+Th expression format in the file is the same as preferred, but the latter can be set through command line (git-annex wanted REPO EXP), but I can't find any way to set required through command line. Is there any way, in the works, or not planned?
+
+Thanks!
+"""]]
diff --git a/doc/special_remotes.mdwn b/doc/special_remotes.mdwn
--- a/doc/special_remotes.mdwn
+++ b/doc/special_remotes.mdwn
@@ -42,6 +42,7 @@
 * [chef-vault](https://github.com/3ofcoins/knife-annex/)
 * [hubiC](https://github.com/Schnouki/git-annex-remote-hubic)
 * [pCloud](https://github.com/tochev/git-annex-remote-pcloud)
+* [[ipfs]]
 
 Want to add support for something else? [[Write your own!|external]]
 
diff --git a/doc/special_remotes/S3/comment_17_52d3510016c099d083553f9b3fa40db9._comment b/doc/special_remotes/S3/comment_17_52d3510016c099d083553f9b3fa40db9._comment
new file mode 100644
--- /dev/null
+++ b/doc/special_remotes/S3/comment_17_52d3510016c099d083553f9b3fa40db9._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="https://www.google.com/accounts/o8/id?id=AItOawlc-3pdibcizrdz4WmZooECL0k6AvM1cWc"
+ nickname="Joe"
+ subject="S3 file/folder names"
+ date="2015-02-19T22:22:26Z"
+ content="""
+Is there a way to tell the S3 backend to store the files as they are named locally, instead of by hashed content name? i.e., I've annexed foo/bar.txt and annex puts it in s3 as mybucket.name/foo/bar.txt instead of mybucket.name/GPGHMACSHA1-random.txt
+
+Or should I just write a script to s3cmd sync my annex, and add the S3/cloudfront distribution URL as a web remote?
+"""]]
diff --git a/doc/special_remotes/external/git-annex-remote-ipfs b/doc/special_remotes/external/git-annex-remote-ipfs
new file mode 100644
--- /dev/null
+++ b/doc/special_remotes/external/git-annex-remote-ipfs
@@ -0,0 +1,125 @@
+#!/bin/sh
+# This is a git-annex external special remote program,
+# which adds experimental ipfs support to git-annex.
+#
+# Install in PATH as git-annex-remote-ipfs
+#
+# Copyright 2015 Joey Hess; licenced under the GNU GPL version 3 or higher.
+
+set -e
+
+# use ipfs: as a prefix to indicate when an "url" is really stored in ipfs
+isipfsurl () {
+	echo "$1" | egrep -q "^ipfs:"
+}
+
+# convert an ipfs: url to an address that the ipfs client understands
+urltoaddress () {
+	echo "$1" | sed -e 's/^ipfs://'
+}
+
+addresstourl () {
+	echo "ipfs:$1"
+}
+
+# Gets a VALUE response and stores it in $RET
+getvalue () {
+	read resp
+	# Tricky POSIX shell code to split first word of the resp,
+	# preserving all other whitespace
+	case "${resp%% *}" in
+		VALUE)
+			RET="$(echo "$resp" | sed 's/^VALUE \?//')"
+		;;
+		*)
+		RET=""
+		;;
+	esac
+}
+
+# Get a list of all known ipfs addresses for a key,
+# storing it in a temp file.
+getaddrs () {
+        key="$1"
+        tmp="$2"
+
+        echo GETURLS "$key"
+        getvalue
+        while [ -n "$RET" ]; do
+                if isipfsurl "$RET"; then
+                        echo "$RET" >> "$tmp"
+                fi
+                getvalue
+        done
+}
+
+# This has to come first, to get the protocol started.
+echo VERSION 1
+
+while read line; do
+	set -- $line
+	case "$1" in
+		INITREMOTE)
+			echo INITREMOTE-SUCCESS
+		;;
+		PREPARE)
+			echo PREPARE-SUCCESS
+		;;
+		CLAIMURL)
+			url="$2"
+			if isipfsurl "$url"; then
+				echo CLAIMURL-SUCCESS
+			else
+				echo CLAIMURL-FAILURE
+			fi
+		;;
+		CHECKURL)
+			url="$2"
+			# TODO if size of file can be quickly determined
+			# (without downloading it) return the size
+			# instead of UNKNOWN
+			echo CHECKURL-CONTENTS UNKNOWN "$(urltoaddress "$url")"
+		;;
+		TRANSFER)
+			key="$3"
+			file="$4"
+			case "$2" in
+				STORE)
+					addr=$(ipfs add -q "$file" </dev/null) || true
+					if [ -z "$addr" ]; then
+						echo TRANSFER-FAILURE STORE "$key" "ipfs add failed"
+					else
+						echo "SETURIPRESENT" "$key" "$(addresstourl "$addr")"
+						echo TRANSFER-SUCCESS STORE "$key"
+					fi
+				;;
+				RETRIEVE)
+					addrtmp=$(mktemp)
+					getaddrs "$key" "$addrtmp"
+					addr="$(urltoaddress "$(head "$addrtmp")")" || true
+					rm -f "$addrtmp"
+					if [ -z "$addr" ]; then
+						echo TRANSFER-FAILURE RETRIEVE "$key" "no known ipfs address for this key"
+					else
+						if ! ipfs get --output="$file" "$addr" >&2 </dev/null; then
+							echo TRANSFER-FAILURE RETRIEVE "$key" "failed downloading ipfs $addr"
+						else
+							echo TRANSFER-SUCCESS RETRIEVE "$key"
+						fi
+					fi
+				;;
+			esac
+		;;
+		CHECKPRESENT)
+			key="$2"
+			echo CHECKPRESENT-FAILURE "$key"
+		;;
+		REMOVE)
+			key="$2"
+			echo REMOVE-FAILURE "$key" "cannot remove content from ipfs (instead, run ipfs gc to clear your local ipfs cache)"
+		;;
+		*)
+			echo UNSUPPORTED-REQUEST
+		;;
+	esac	
+done
diff --git a/doc/special_remotes/ipfs.mdwn b/doc/special_remotes/ipfs.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/special_remotes/ipfs.mdwn
@@ -0,0 +1,85 @@
+This special remote stores file contents in [ipfs](http://ipfs.io/).
+
+Warning: As this page is being written, ipfs is still considered alpha
+quality code, not suitable for production use. Still, it's fun to play
+with, has some nice features and great potential, and git-annex can
+keep your data safe while you're using ipfs.
+
+## prerequisites
+
+* git-annex version 5.20150305 or newer.
+* Install [[external/git-annex-remote-ipfs]] somewhere in PATH
+  and `chmod +x` the script.
+* Install [go-ipfs](https://github.com/jbenet/go-ipfs) somewhere in PATH.
+* Run `ipfs init` and start the `ipfs daemon`
+
+(Note that this special remote does not use ipfs's FUSE support; it
+communicates with ipfs using the `ipfs` command-line utility.)
+
+## configuration
+
+These parameters can be passed to `git annex initremote` to configure the
+remote:
+
+* `encryption` - One of "none", "hybrid", "shared", or "pubkey".
+  See [[encryption]]. Note that this is git-annex's encryption, not ipfs's
+  encryption.
+
+* `keyid` - Specifies the gpg key to use for [[encryption]].
+
+Setup example:
+
+	# git annex initremote ipfs type=external externaltype=ipfs encryption=none
+
+## content distribution
+
+After `git annex copy --to ipfs`, a file will typically only have
+been copied to your computer's local ipfs object store. It will not reach
+other ipfs nodes on the network until they request the content.
+
+If you set up a clone of your repository on another computer, and install
+ipfs and enable the ipfs remote there, you can proceed with using it to get
+files that have been stored in ipfs:
+
+	# git annex sync
+	# git annex enableremote ipfs
+	# git annex copy --from ipfs
+
+## content removal
+
+Removing content from ipfs requires all nodes that have a copy to decide to
+delete it. This is not something git-annex can arrange to happen, or
+reliably tell has happened, so `git annex drop --from ipfs` will always fail.
+
+## using ipfs addresses
+
+Once a file has been copied to ipfs, you can use `git annex whereis`
+to look up the ipfs address of the file:
+
+	# git annex whereis somefile
+	whereis somefile
+		ed1c811d-fe42-4436-aa75-56566c990aa8 -- ipfs
+	
+	ipfs: ipfs:QmYgXEfjsLbPvVKrrD4Hf6QvXYRPRjH5XFGajDqtxBnD4W
+
+In the example above, the ipfs address for the file is
+`QmYgXEfjsLbPvVKrrD4Hf6QvXYRPRjH5XFGajDqtxBnD4W`. You can give this
+address to any other ipfs user and they can use it to download the file!
+
+You can also use ipfs addresses with `git annex addurl`. For example:
+
+	# git annex addurl ipfs:QmYgXEfjsLbPvVKrrD4Hf6QvXYRPRjH5XFGajDqtxBnD4W --file somefile
+
+That's a real file; try it!
+
+## future directions
+
+While perhaps useful, this is just a proof of concept. It's particularly
+lacking in that it doesn't integrate well git-annex's [[location_tracking]]
+with ipfs. 
+
+Tracking which ipfs nodes have a copy of an annexed object
+would make this special remote work better. In particular, git-annex does
+not currently trust ipfs to contain a copy of an object, since it has no
+way of keeping track of which which ipfs nodes might contain it. So, eg, 
+`git annex drop` will refuse to trust ipfs.
diff --git a/doc/special_remotes/ipfs/comment_1_d1b2da148715476015716a2f866558b9._comment b/doc/special_remotes/ipfs/comment_1_d1b2da148715476015716a2f866558b9._comment
new file mode 100644
--- /dev/null
+++ b/doc/special_remotes/ipfs/comment_1_d1b2da148715476015716a2f866558b9._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="https://id.koumbit.net/anarcat"
+ subject="about copying to the local store"
+ date="2015-03-07T13:16:02Z"
+ content="""
+there's a [discussion](https://github.com/jbenet/go-ipfs/issues/875) happening upstream about how copying to the local datastore could be avoided.
+"""]]
diff --git a/doc/submodules.mdwn b/doc/submodules.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/submodules.mdwn
@@ -0,0 +1,22 @@
+[Git submodules](http://git-scm.com/book/en/v2/Git-Tools-Submodules) are
+supported by git-annex since version 5.20150303.
+
+Git normally makes a `.git` **file** in a
+submodule, that points to the real git repository under `.git/modules/`.
+This presents problems for git-annex. So, when used in a submodule,
+git-annex will automatically replace the `.git` file with a symlink
+pointing at the git repository. (When the filesystem doesn't support
+symlinks, direct mode is used, and submodules are supported in that
+setup too.)
+
+With that taken care of, git-annex should work ok in submodules. Although
+this is a new and somewhat experimental feature.
+
+The conversion of .git file to .git symlink mostly won't bother git.
+
+Known problems:
+
+* If you want to delete a whole submodule, `git rm submodule`
+  will refuse to delete it, complaining that the
+  submodule "uses a .git directory". Workaround: Use `rm -rf`
+  to delete the tree, and then `git commit`.
diff --git a/doc/todo/Add_gitlab.com_as_cloud_provider.mdwn b/doc/todo/Add_gitlab.com_as_cloud_provider.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/todo/Add_gitlab.com_as_cloud_provider.mdwn
@@ -0,0 +1,7 @@
+Hi,
+
+[I don't know if this should go to todo or bugs or should be plainly ignored.  Hope it's OK].
+
+Gitlab.com and Gitlab enterprise edition, but unfortunately not Gitlab community edition, now [provides git annex support](https://about.gitlab.com/2015/02/17/gitlab-annex-solves-the-problem-of-versioning-large-binaries-with-git/).  It works fairly based for the repos I have enabled it on.  At the moment it's free, but one may have to pay for repos larger than 5Gb [in the future](https://about.gitlab.com/2015/02/22/gitlab-7-8-released/#comment-1870271594).
+
+Perhaps gitlab.com should be added to preconfigured cloud providers?
diff --git a/doc/todo/Facilitate_public_pretty_S3_URLs.mdwn b/doc/todo/Facilitate_public_pretty_S3_URLs.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/todo/Facilitate_public_pretty_S3_URLs.mdwn
@@ -0,0 +1,16 @@
+I archive all my photos/video to a bucket CNAMED to http://s.natalian.org/ with a simple YYYY-MM-DD prefix.
+
+E.g. <http://s.natalian.org/2015-03-06/1425615579_1918x1060.png>
+
+I'm not doing a great job of backing up the S3 bucket to another S3 compatible host, since `s3cmd sync`/`aws sync` is so slow, but that's beside the point. Ideally it could be tracked by **git-annex**!
+
+Adding all the objects into git-annex, IIUC currently would require me:
+
+* to download the ~80GB and then add them to git-annex
+* there is no way to keep my current S3 URLs with the [[special_remotes/S3]] since `git-annex` has it's own special way of storing to a bucket, e.g. https://s3-ap-southeast-1.amazonaws.com/s3-10418340-834d-41c2-b38f-7ee84bf6a23a/SHA256E-s1034208123--235e4f288d094c2e1870bc3d9d353abf34542c04c1d26905e882718a7ccf74cf.mp4 - I'd rather not have HTTP redirects
+* AFAICT there is no way currently with git-annex to mark the [[special_remotes/S3]] as public, which is needed for public URLs to work
+* AFAICT there is no current automated method the mapping via `git-annex addurl` with the public URLs of the each file in the bucket
+
+The ideal solution in my mind is for git-annex to track the contents of S3 as they are now, preserving the URLs and tracking the checksums in a separate index file.
+
+Thank you!
diff --git a/doc/todo/Nearline_support.mdwn b/doc/todo/Nearline_support.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/todo/Nearline_support.mdwn
@@ -0,0 +1,6 @@
+This has been described as Google's [[special_remotes/glacier]].
+
+* [Announcement](http://googlecloudplatform.blogspot.in/2015/03/introducing-Google-Cloud-Storage-Nearline-near-online-data-at-an-offline-price.html)
+* <https://cloud.google.com/storage/docs/nearline-storage>
+
+> [[dup|done]] --[[Joey]]
diff --git a/doc/todo/Shorten_long_file_names_preventing_git_checkout.mdwn b/doc/todo/Shorten_long_file_names_preventing_git_checkout.mdwn
new file mode 100644
--- /dev/null
+++ b/doc/todo/Shorten_long_file_names_preventing_git_checkout.mdwn
@@ -0,0 +1,14 @@
+Submitting here from https://github.com/joeyh/git-annex/pull/36
+
+    commit 05b7e0d2e87c1c92df773d72ee0ac7c9638be058
+    Author: Eric OConnor <eric@oco.nnor.org>
+
+> I've applied this patch. Thanks Eric. 
+> 
+> Of course, nothing is preventing filenames > 255 being added in the
+> future. Based on the number that had to be renamed, this is pretty low
+> probability, but it does happen. It would need changes to ikiwiki to add
+> an enforced limit. If someone wants to patch ikiwiki that way, I'll
+> enable it.
+>
+> For now, [[done]]. --[[Joey]]
diff --git a/git-annex.1 b/git-annex.1
--- a/git-annex.1
+++ b/git-annex.1
@@ -219,6 +219,10 @@
 Urls to torrent files (including magnet links) will cause the content of
 the torrent to be downloaded, using \fBaria2c\fP.
 .IP
+To prevent special handling of urls by quvi, bittorrent, and other
+special remotes, specify \fB\-\-raw\fP. This will for example, make addurl
+download the .torrent file and not the contents it points to.
+.IP
 .IP "\fBrmurl file url\fP"
 Record that the file is no longer available at the url.
 .IP
@@ -269,7 +273,8 @@
 The default template is '${feedtitle}/${itemtitle}${extension}'
 (Other available variables: feedauthor, itemauthor, itemsummary, itemdescription, itemrights, itemid, itempubdate, title, author)
 .IP
-The \fB\-\-relaxed\fP and \fB\-\-fast\fP options behave the same as they do in addurl.
+The \fB\-\-relaxed\fP, \fB\-\-fast\fP, and \fB\-\-raw\fP options behave the same as they
+do in addurl.
 .IP
 When quvi is installed, links in the feed are tested to see if they
 are on a video hosting site, and the video is downloaded. This allows
@@ -648,7 +653,7 @@
 the mtime field of a WORM key).
 .IP
 .IP "\fBwhereis [path ...]\fP"
-Displays a information about where the contents of files are located.
+Displays information about where the contents of files are located.
 .IP
 .IP "\fBlist [path ...]\fP"
 Displays a table of remotes that contain the contents of the specified
@@ -877,10 +882,27 @@
 .IP
  git annex examinekey \-\-format='.git/annex/objects/${hashdirmixed}${key}/${key}'
 .IP
-.IP "\fBfromkey key file\fP"
+.IP "\fBfromkey [key file]\fP"
 This plumbing\-level command can be used to manually set up a file
 in the git repository to link to a specified key.
 .IP
+Normally, the annex needs to already contain the content object for the
+key. To override this, use \-\-force.
+.IP
+If the key and file are not specified on the command line, they are
+instead read from stdin. Any number of lines can be provided in this
+mode, each containing a key and filename, sepearated by whitespace.
+.IP
+.IP "\fBregisterurl [key url]\fP"
+This plumbing\-level command can be used to register urls where a
+key can be downloaded from.
+.IP
+No verification is performed of the url's contents.
+.IP
+If the key and url are not specified on the command line, they are
+instead read from stdin. Any number of lines can be provided in this
+mode, each containing a key and url, sepearated by whitespace.
+.IP
 .IP "\fBdropkey [key ...]\fP"
 This plumbing\-level command drops the annexed data for the specified
 keys from this repository.
@@ -1262,9 +1284,12 @@
 .PP
 When a repository is in one of the standard predefined groups, like "backup"
 and "client", setting its preferred content to "standard" will use a
-built\-in preferred content expression developed for that group. Or,
-setting its preferred content to "groupwanted" will make it use whatever
-groupwanted expression you set for the group.
+built\-in preferred content expression developed for that group. 
+See <https://git\-annex.branchable.com/preferred_content/standard_groups/>
+.PP
+If you have set a groupwanted expression for a group, it will be used
+when a repository in the group has its preferred content set to
+"groupwanted".
 .PP
 .SH SCHEDULED JOBS
 The git\-annex assistant daemon can be configured to run scheduled jobs.
diff --git a/git-annex.cabal b/git-annex.cabal
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -1,5 +1,5 @@
 Name: git-annex
-Version: 5.20150219
+Version: 5.20150317
 Cabal-Version: >= 1.8
 License: GPL-3
 Maintainer: Joey Hess <id@joeyh.name>
@@ -110,7 +110,9 @@
    IfElse, text, QuickCheck >= 2.1, bloomfilter, edit-distance,
    SafeSemaphore, uuid, random, dlist, unix-compat, async, stm (>= 2.3),
    data-default, case-insensitive, http-conduit, http-types,
-   cryptohash (>= 0.10.0)
+   cryptohash (>= 0.10.0),
+   esqueleto, persistent-sqlite, persistent, persistent-template,
+   monad-logger, resourcet
   CC-Options: -Wall
   GHC-Options: -Wall
   Extensions: PackageImports
@@ -148,7 +150,7 @@
     Build-Depends: regex-compat
 
   if flag(S3)
-    Build-Depends: conduit, resourcet, conduit-extra, aws (>= 0.9.2), http-client
+    Build-Depends: conduit, conduit-extra, aws (>= 0.9.2), http-client
     CPP-Options: -DWITH_S3
 
   if flag(WebDAV)
@@ -220,7 +222,7 @@
     CPP-Options: -DWITH_DNS
 
   if flag(Feed)
-    Build-Depends: feed
+    Build-Depends: feed (>= 0.3.4)
     CPP-Options: -DWITH_FEED
   
   if flag(Quvi)
diff --git a/standalone/linux/skel/runshell b/standalone/linux/skel/runshell
--- a/standalone/linux/skel/runshell
+++ b/standalone/linux/skel/runshell
@@ -74,6 +74,10 @@
 GCONV_PATH=$base/$(cat $base/gconvdir)
 export GCONV_PATH
 
+# workaround for https://ghc.haskell.org/trac/ghc/ticket/7695
+LOCPATH=/dev/null
+export LOCPATH
+
 ORIG_GIT_EXEC_PATH="$GIT_EXEC_PATH"
 export ORIG_GIT_EXEC_PATH
 GIT_EXEC_PATH=$base/git-core
diff --git a/standalone/no-th/evilsplicer-headers.hs b/standalone/no-th/evilsplicer-headers.hs
--- a/standalone/no-th/evilsplicer-headers.hs
+++ b/standalone/no-th/evilsplicer-headers.hs
@@ -10,6 +10,8 @@
 import qualified Data.Set as Data.Set.Base
 import qualified Data.Map
 import qualified Data.Map as Data.Map.Base
+import qualified Data.HashMap.Strict
+import qualified Data.HashMap.Strict as Data.HashMap.Base
 import qualified Data.Foldable
 import qualified Data.Text
 import qualified Data.Text.Lazy.Builder
@@ -33,6 +35,14 @@
 import qualified GHC.IO
 import qualified Data.ByteString.Unsafe
 import qualified Data.ByteString.Char8
+import qualified Database.Persist.Class as Database.Persist.Class.PersistField
+import qualified Database.Persist as Database.Persist.Class.PersistField
+import qualified Database.Persist.Sql as Database.Persist.Sql.Class
+import qualified Database.Persist.Sql as Database.Persist.Types.Base
+import qualified Control.Monad.Logger
+import qualified Control.Monad.IO.Class
+import qualified Control.Monad.Trans.Control
+import Database.Persist.Sql (fromPersistValue)
 {- End EvilSplicer headers. -}
 
 
diff --git a/standalone/no-th/haskell-patches/persistent-template_stub-out.patch b/standalone/no-th/haskell-patches/persistent-template_stub-out.patch
--- a/standalone/no-th/haskell-patches/persistent-template_stub-out.patch
+++ b/standalone/no-th/haskell-patches/persistent-template_stub-out.patch
@@ -1,25 +1,68 @@
-From e6542197f1da6984bb6cd3310dba77363dfab2d9 Mon Sep 17 00:00:00 2001
-From: dummy <dummy@example.com>
-Date: Thu, 16 Oct 2014 01:51:02 +0000
-Subject: [PATCH] stub out
+From b22a4d77c1262f77ce4298b53ca90a138a14ceb7 Mon Sep 17 00:00:00 2001
+From: Joey Hess <joeyh@joeyh.name>
+Date: Sun, 22 Feb 2015 15:21:19 -0400
+Subject: [PATCH] stub out TH
 
+this method avoids needing to delete the entire file contents, so patch is
+kept minimal
 ---
- persistent-template.cabal | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
+ Database/Persist/TH.hs      |  1 +
+ persistent-template.cabal   |  1 +
+ stub/Database/Persist/TH.hs | 21 +++++++++++++++++++++
+ 3 files changed, 23 insertions(+)
+ create mode 100644 stub/Database/Persist/TH.hs
 
+diff --git a/Database/Persist/TH.hs b/Database/Persist/TH.hs
+index 43eb3ee..2172b77 100644
+--- a/Database/Persist/TH.hs
++++ b/Database/Persist/TH.hs
+@@ -35,6 +35,7 @@ module Database.Persist.TH
+       -- * Internal
+     , packPTH
+     , lensPTH
++    , plusPlus
+     ) where
+ 
+ import Prelude hiding ((++), take, concat, splitAt)
 diff --git a/persistent-template.cabal b/persistent-template.cabal
-index 59b4149..e11b418 100644
+index 59b4149..4705d97 100644
 --- a/persistent-template.cabal
 +++ b/persistent-template.cabal
-@@ -26,7 +26,7 @@ library
-                    , aeson
-                    , monad-logger
-                    , unordered-containers
--    exposed-modules: Database.Persist.TH
-+    exposed-modules: 
+@@ -30,6 +30,7 @@ library
      ghc-options:     -Wall
      if impl(ghc >= 7.4)
         cpp-options: -DGHC_7_4
++    hs-source-dirs: stub
+ 
+ test-suite test
+     type:          exitcode-stdio-1.0
+diff --git a/stub/Database/Persist/TH.hs b/stub/Database/Persist/TH.hs
+new file mode 100644
+index 0000000..dfbb874
+--- /dev/null
++++ b/stub/Database/Persist/TH.hs
+@@ -0,0 +1,21 @@
++{-# LANGUAGE RecordWildCards #-}
++{-# LANGUAGE CPP #-}
++{-# LANGUAGE OverloadedStrings #-}
++{-# LANGUAGE RankNTypes #-}
++{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-missing-fields #-}
++-- | This module provides utilities for creating backends. Regular users do not
++-- need to use this module.
++module Database.Persist.TH where
++
++import Data.Text
++
++type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
++
++lensPTH :: (s -> a) -> (s -> b -> t) -> Lens s t a b
++lensPTH sa sbt afb s = fmap (sbt s) (afb $ sa s)
++
++packPTH :: String -> Text
++packPTH = pack
++#if !MIN_VERSION_text(0, 11, 2)
++{-# NOINLINE packPTH #-}
++#endif
 -- 
-2.1.1
+2.1.4
 
