diff --git a/Annex.hs b/Annex.hs
--- a/Annex.hs
+++ b/Annex.hs
@@ -77,7 +77,7 @@
  - The MVar is not exposed outside this module.
  -
  - Note that when an Annex action fails and the exception is caught,
- - ny changes the action has made to the AnnexState are retained,
+ - any changes the action has made to the AnnexState are retained,
  - due to the use of the MVar to store the state.
  -}
 newtype Annex a = Annex { runAnnex :: ReaderT (MVar AnnexState) IO a }
@@ -135,56 +135,60 @@
 	, desktopnotify :: DesktopNotify
 	, workers :: [Either AnnexState (Async AnnexState)]
 	, concurrentjobs :: Maybe Int
+	, activeremotes :: MVar (S.Set (Types.Remote.RemoteA Annex))
 	, keysdbhandle :: Maybe Keys.DbHandle
 	, cachedcurrentbranch :: Maybe Git.Branch
 	}
 
-newState :: GitConfig -> Git.Repo -> AnnexState
-newState c r = AnnexState
-	{ repo = r
-	, repoadjustment = return
-	, gitconfig = c
-	, backends = []
-	, remotes = []
-	, remoteannexstate = M.empty
-	, output = def
-	, force = False
-	, fast = False
-	, daemon = False
-	, branchstate = startBranchState
-	, repoqueue = Nothing
-	, catfilehandles = M.empty
-	, hashobjecthandle = Nothing
-	, checkattrhandle = Nothing
-	, checkignorehandle = Nothing
-	, forcebackend = Nothing
-	, globalnumcopies = Nothing
-	, forcenumcopies = Nothing
-	, limit = BuildingMatcher []
-	, uuidmap = Nothing
-	, preferredcontentmap = Nothing
-	, requiredcontentmap = Nothing
-	, forcetrust = M.empty
-	, trustmap = Nothing
-	, groupmap = Nothing
-	, ciphers = M.empty
-	, lockcache = M.empty
-	, flags = M.empty
-	, fields = M.empty
-	, cleanup = M.empty
-	, sentinalstatus = Nothing
-	, useragent = Nothing
-	, errcounter = 0
-	, unusedkeys = Nothing
-	, tempurls = M.empty
-	, quviversion = Nothing
-	, existinghooks = M.empty
-	, desktopnotify = mempty
-	, workers = []
-	, concurrentjobs = Nothing
-	, keysdbhandle = Nothing
-	, cachedcurrentbranch = Nothing
-	}
+newState :: GitConfig -> Git.Repo -> IO AnnexState
+newState c r = do
+	emptyactiveremotes <- newMVar S.empty
+	return $ AnnexState
+		{ repo = r
+		, repoadjustment = return
+		, gitconfig = c
+		, backends = []
+		, remotes = []
+		, remoteannexstate = M.empty
+		, output = def
+		, force = False
+		, fast = False
+		, daemon = False
+		, branchstate = startBranchState
+		, repoqueue = Nothing
+		, catfilehandles = M.empty
+		, hashobjecthandle = Nothing
+		, checkattrhandle = Nothing
+		, checkignorehandle = Nothing
+		, forcebackend = Nothing
+		, globalnumcopies = Nothing
+		, forcenumcopies = Nothing
+		, limit = BuildingMatcher []
+		, uuidmap = Nothing
+		, preferredcontentmap = Nothing
+		, requiredcontentmap = Nothing
+		, forcetrust = M.empty
+		, trustmap = Nothing
+		, groupmap = Nothing
+		, ciphers = M.empty
+		, lockcache = M.empty
+		, flags = M.empty
+		, fields = M.empty
+		, cleanup = M.empty
+		, sentinalstatus = Nothing
+		, useragent = Nothing
+		, errcounter = 0
+		, unusedkeys = Nothing
+		, tempurls = M.empty
+		, quviversion = Nothing
+		, existinghooks = M.empty
+		, desktopnotify = mempty
+		, workers = []
+		, concurrentjobs = Nothing
+		, activeremotes = emptyactiveremotes
+		, keysdbhandle = Nothing
+		, cachedcurrentbranch = Nothing
+		}
 
 {- Makes an Annex state object for the specified git repo.
  - Ensures the config is read, if it was not already, and performs
@@ -193,7 +197,7 @@
 new r = do
 	r' <- Git.Config.read =<< Git.relPath r
 	let c = extractGitConfig r'
-	newState c <$> fixupRepo r' c
+	newState c =<< fixupRepo r' c
 
 {- Performs an action in the Annex monad from a starting state,
  - returning a new state. -}
diff --git a/Annex/Transfer.hs b/Annex/Transfer.hs
--- a/Annex/Transfer.hs
+++ b/Annex/Transfer.hs
@@ -1,11 +1,11 @@
 {- git-annex transfers
  -
- - Copyright 2012-2014 Joey Hess <id@joeyh.name>
+ - Copyright 2012-2016 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU GPL version 3 or higher.
  -}
 
-{-# LANGUAGE CPP, FlexibleInstances #-}
+{-# LANGUAGE CPP, FlexibleInstances, BangPatterns #-}
 
 module Annex.Transfer (
 	module X,
@@ -15,9 +15,11 @@
 	alwaysRunTransfer,
 	noRetry,
 	forwardRetry,
+	pickRemote,
 ) where
 
 import Annex.Common
+import qualified Annex
 import Logs.Transfer as X
 import Types.Transfer as X
 import Annex.Notification as X
@@ -25,8 +27,10 @@
 import Utility.Metered
 import Annex.LockPool
 import Types.Remote (Verification(..))
+import qualified Types.Remote as Remote
 
 import Control.Concurrent
+import qualified Data.Set as S
 
 class Observable a where
 	observeBool :: a -> Bool
@@ -166,3 +170,56 @@
  - to send some data. -}
 forwardRetry :: RetryDecider
 forwardRetry old new = bytesComplete old < bytesComplete new
+
+{- Picks a remote from the list and tries a transfer to it. If the transfer
+ - does not succeed, goes on to try other remotes from the list.
+ -
+ - The list should already be ordered by remote cost, and is normally
+ - tried in order. However, when concurrent jobs are running, they will
+ - be assigned different remotes of the same cost when possible. This can
+ - increase total transfer speed.
+ -}
+pickRemote :: Observable v => [Remote] -> (Remote -> Annex v) -> Annex v
+pickRemote l a = go l =<< Annex.getState Annex.concurrentjobs
+  where
+	go [] _ = return observeFailure
+	go (r:[]) _ = a r
+	go rs (Just n) | n > 1 = do
+		mv <- Annex.getState Annex.activeremotes
+		active <- liftIO $ takeMVar mv
+		let rs' = sortBy (inactiveFirst active) rs
+		goconcurrent mv active rs'
+	go (r:rs) _ = do
+		ok <- a r
+		if observeBool ok
+			then return ok
+			else go rs Nothing
+	goconcurrent mv active [] = do
+		liftIO $ putMVar mv active
+		return observeFailure
+	goconcurrent mv active (r:rs) = do
+		let !active' = S.insert r active
+		liftIO $ putMVar mv active'
+		let getnewactive = do
+			active'' <- liftIO $ takeMVar mv
+			let !active''' = S.delete r active''
+			return active'''
+		let removeactive = liftIO . putMVar mv =<< getnewactive
+		ok <- a r `onException` removeactive
+		if observeBool ok
+			then do
+				removeactive
+				return ok 
+			else do
+				active'' <- getnewactive
+				-- Re-sort the remaining rs 
+				-- because other threads could have
+				-- been assigned them in the meantime.
+				let rs' = sortBy (inactiveFirst active'') rs
+				goconcurrent mv active'' rs'
+
+inactiveFirst :: S.Set Remote -> Remote -> Remote -> Ordering
+inactiveFirst active a b
+	| Remote.cost a == Remote.cost b =
+		if a `S.member` active then GT else LT
+	| otherwise = compare a b
diff --git a/Assistant/Pairing/Network.hs b/Assistant/Pairing/Network.hs
--- a/Assistant/Pairing/Network.hs
+++ b/Assistant/Pairing/Network.hs
@@ -20,6 +20,8 @@
 import Network.Multicast
 import Network.Info
 import Network.Socket
+import qualified Network.Socket.ByteString as B
+import qualified Data.ByteString.UTF8 as BU8
 import qualified Data.Map as M
 import Control.Concurrent
 
@@ -63,10 +65,11 @@
 		withSocketsDo $ bracket setup cleanup use
 	  where
 		setup = multicastSender (multicastAddress IPv4AddrClass) pairingPort
-		cleanup (sock, _) = sClose sock -- FIXME does not work
+		cleanup (sock, _) = close sock -- FIXME does not work
 		use (sock, addr) = do
 			setInterface sock (showAddr i)
-			maybe noop (\s -> void $ sendTo sock s addr)
+			maybe noop
+				(\s -> void $ B.sendTo sock (BU8.fromString s) addr)
 				(M.lookup i cache)
 	updatecache cache [] = cache
 	updatecache cache (i:is)
diff --git a/Assistant/Threads/PairListener.hs b/Assistant/Threads/PairListener.hs
--- a/Assistant/Threads/PairListener.hs
+++ b/Assistant/Threads/PairListener.hs
@@ -20,6 +20,9 @@
 
 import Network.Multicast
 import Network.Socket
+import qualified Data.ByteString as B
+import qualified Data.ByteString.UTF8 as BU8
+import qualified Network.Socket.ByteString as B
 import qualified Data.Text as T
 
 pairListenerThread :: UrlRenderer -> NamedThread
@@ -33,7 +36,7 @@
 	 - or only one like lo that doesn't support multicast. -}
 	getsock = multicastReceiver (multicastAddress IPv4AddrClass) pairingPort
 		
-	go reqs cache sock = liftIO (getmsg sock []) >>= \msg -> case readish msg of
+	go reqs cache sock = liftIO (getmsg sock B.empty) >>= \msg -> case readish (BU8.toString msg) of
 		Nothing -> go reqs cache sock
 		Just m -> do
 			debug ["received", show msg]
@@ -94,10 +97,10 @@
 	invalidateCache msg = filter (not . verifiedPairMsg msg)
 
 	getmsg sock c = do
-		(msg, n, _) <- recvFrom sock chunksz
-		if n < chunksz
-			then return $ c ++ msg
-			else getmsg sock $ c ++ msg
+		(msg, _) <- B.recvFrom sock chunksz
+		if B.length msg < chunksz
+			then return $ c <> msg
+			else getmsg sock $ c <> msg
 	  where
 		chunksz = 1024
 
diff --git a/Build/Configure.hs b/Build/Configure.hs
--- a/Build/Configure.hs
+++ b/Build/Configure.hs
@@ -5,7 +5,6 @@
 module Build.Configure where
 
 import Control.Applicative
-import System.Environment (getArgs)
 import Control.Monad.IfElse
 import Control.Monad
 
@@ -133,12 +132,12 @@
 
 run :: [TestCase] -> IO ()
 run ts = do
-	args <- getArgs
 	setup
 	config <- runTests ts
-	if args == ["Android"]
-		then writeSysConfig $ androidConfig config
-		else writeSysConfig config
+	v <- getEnv "CROSS_COMPILE"
+	case v of
+		Just "Android" -> writeSysConfig $ androidConfig config
+		_ -> writeSysConfig config
 	cleanup
 	whenM isReleaseBuild $
 		cabalSetup "git-annex.cabal"
diff --git a/Build/mdwn2man b/Build/mdwn2man
--- a/Build/mdwn2man
+++ b/Build/mdwn2man
@@ -10,7 +10,7 @@
 	s{(\\?)\[\[([^\s\|\]]+)(\|[^\s\]]+)?\]\]}{$1 ? "[[$2]]" : $2}eg;
 	s/\`([^\`]*)\`/\\fB$1\\fP/g;
 	s/\`//g;
-	s/^\s*\./\\&./g;
+	s/^ *\./\\&./g;
 	if (/^#\s/) {
 		s/^#\s/.SH /;
 		<>; # blank;
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,21 @@
+git-annex (6.20160907) unstable; urgency=medium
+
+  * Windows: Handle shebang in external special remote program.
+  * Fix formatting of git-annex-smudge man page, and improve mdwn2man.
+    Thanks, Jim Paris.
+  * examimekey: Allow being run in a git repo that is not initialized by
+    git-annex yet.
+  * Android: Fix disabling use of cp --reflink=auto, curl, sha224, and sha384.
+  * Make --json and --quiet suppress automatic init messages, and any
+    other messages that might be output before a command starts.
+    Fixes a reversion introduced in version 5.20150727.
+  * Assistant, repair: Filter out git fsck lines about duplicate file
+    entries in tree objects.
+  * get -J, sync --content -J: Download different files from different
+    remotes when the remotes have the same costs.
+
+ -- Joey Hess <id@joeyh.name>  Wed, 07 Sep 2016 11:12:11 -0400
+
 git-annex (6.20160808) unstable; urgency=medium
 
   * metadata --json output format has changed, adding a inner json object
diff --git a/CmdLine.hs b/CmdLine.hs
--- a/CmdLine.hs
+++ b/CmdLine.hs
@@ -99,7 +99,7 @@
 	mkparser c = (,,) 
 		<$> pure c
 		<*> getparser c
-		<*> combineGlobalOptions globaloptions
+		<*> combineGlobalOptions (globaloptions ++ cmdglobaloptions c)
 	synopsis n d = n ++ " - " ++ d
 	intro = mconcat $ concatMap (\l -> [H.text l, H.line])
 		(synopsis progname progdesc : commandList allcmds)
diff --git a/Command.hs b/Command.hs
--- a/Command.hs
+++ b/Command.hs
@@ -33,7 +33,7 @@
 command :: String -> CommandSection -> String -> CmdParamsDesc -> (CmdParamsDesc -> CommandParser) -> Command
 command name section desc paramdesc mkparser =
 	Command commonChecks False False name paramdesc 
-		section desc (mkparser paramdesc) Nothing
+		section desc (mkparser paramdesc) [] Nothing
 
 {- Simple option parser that takes all non-option params as-is. -}
 withParams :: (CmdParams -> v) -> CmdParamsDesc -> Parser v
@@ -68,18 +68,9 @@
 noRepo :: (String -> Parser (IO ())) -> Command -> Command
 noRepo a c = c { cmdnorepo = Just (a (cmdparamdesc c)) }
 
-{- Adds global options to a command's option parser, and modifies its seek
- - option to first run actions for them.
- -}
+{- Adds global options to a command's. -}
 withGlobalOptions :: [GlobalOption] -> Command -> Command
-withGlobalOptions os c = c { cmdparser = apply <$> mixin (cmdparser c) }
-  where
-	mixin p = (,) 
-		<$> p
-		<*> combineGlobalOptions os
-	apply (seek, globalsetters) = do
-		void $ getParsed globalsetters
-		seek
+withGlobalOptions os c = c { cmdglobaloptions = cmdglobaloptions c ++ os }
 
 {- For start and perform stages to indicate what step to run next. -}
 next :: a -> Annex (Maybe a)
diff --git a/Command/ExamineKey.hs b/Command/ExamineKey.hs
--- a/Command/ExamineKey.hs
+++ b/Command/ExamineKey.hs
@@ -12,11 +12,12 @@
 import Command.Find (parseFormatOption, showFormatted, keyVars)
 
 cmd :: Command
-cmd = noCommit $ noMessages $ withGlobalOptions [jsonOption] $
-	command "examinekey" SectionPlumbing 
-		"prints information from a key"
-		(paramRepeating paramKey)
-		(batchable run (optional parseFormatOption))
+cmd = noCommit $ noMessages $ dontCheck repoExists $ 
+	withGlobalOptions [jsonOption] $
+		command "examinekey" SectionPlumbing 
+			"prints information from a key"
+			(paramRepeating paramKey)
+			(batchable run (optional parseFormatOption))
 
 run :: Maybe Utility.Format.Format -> String -> Annex Bool
 run format p = do
diff --git a/Command/Get.hs b/Command/Get.hs
--- a/Command/Get.hs
+++ b/Command/Get.hs
@@ -89,16 +89,17 @@
 		showNote "not available"
 		showlocs
 		return False
-	dispatch remotes = notifyTransfer Download afile $ trycopy remotes remotes
-	trycopy full [] _ = do
-		Remote.showTriedRemotes full
-		showlocs
-		return False
-	trycopy full (r:rs) witness =
-		ifM (probablyPresent r)
-			( docopy r witness <||> trycopy full rs witness
-			, trycopy full rs witness
+	dispatch remotes = notifyTransfer Download afile $ \witness -> do
+		ok <- pickRemote remotes $ \r -> ifM (probablyPresent r)
+			( docopy r witness
+			, return False
 			)
+		if ok
+			then return ok
+			else do
+				Remote.showTriedRemotes remotes
+				showlocs
+				return False
 	showlocs = Remote.showLocations False key []
 		"No other repository is known to contain the file."
 	-- This check is to avoid an ugly message if a remote is a
diff --git a/Command/Sync.hs b/Command/Sync.hs
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -43,7 +43,6 @@
 import Annex.Content
 import Command.Get (getKey')
 import qualified Command.Move
-import Logs.Location
 import Annex.Drop
 import Annex.UUID
 import Logs.UUID
@@ -470,7 +469,7 @@
  -}
 syncFile :: Either (Maybe (Bloom Key)) (Key -> Annex ()) -> [Remote] -> AssociatedFile -> Key -> Annex Bool
 syncFile ebloom rs af k = do
-	locs <- loggedLocations k
+	locs <- Remote.keyLocations k
 	let (have, lack) = partition (\r -> Remote.uuid r `elem` locs) rs
 
 	got <- anyM id =<< handleget have
diff --git a/Git/Fsck.hs b/Git/Fsck.hs
--- a/Git/Fsck.hs
+++ b/Git/Fsck.hs
@@ -104,6 +104,8 @@
 findShas supportsNoDangling = catMaybes . map extractSha . concat . map words . filter wanted . lines
   where
 	wanted l
+		-- Skip lines like "error in tree <sha>: duplicateEntries: contains duplicate file entries"
+		| "duplicateEntries" `isPrefixOf` l = False
 		| supportsNoDangling = True
 		| otherwise = not ("dangling " `isPrefixOf` l)
 
diff --git a/Git/Hook.hs b/Git/Hook.hs
--- a/Git/Hook.hs
+++ b/Git/Hook.hs
@@ -12,6 +12,7 @@
 import Common
 import Git
 import Utility.Tmp
+import Utility.Shell
 #ifndef mingw32_HOST_OS
 import Utility.FileMode
 #endif
@@ -75,23 +76,5 @@
 runHook :: Hook -> Repo -> IO Bool
 runHook h r = do
 	let f = hookFile h r
-	(c, ps) <- findcmd f
+	(c, ps) <- findShellCommand f
 	boolSystem c ps
-  where
-#ifndef mingw32_HOST_OS
-	findcmd = defcmd
-#else
-	{- Like git for windows, parse the first line of the hook file,
-	 - look for "#!", and dispatch the interpreter on the file. -}
-	findcmd f = do
-		l <- headMaybe . lines <$> catchDefaultIO "" (readFile f)
-		case l of
-			Just ('#':'!':rest) -> case words rest of
-				[] -> defcmd f
-				(c:ps) -> do
-					let ps' = map Param (ps ++ [f])
-					ok <- inPath c
-					return (if ok then c else takeFileName c, ps')
-			_ -> defcmd f
-#endif
-	defcmd f = return (f, [])
diff --git a/Logs/Transfer.hs b/Logs/Transfer.hs
--- a/Logs/Transfer.hs
+++ b/Logs/Transfer.hs
@@ -15,7 +15,6 @@
 import qualified Git
 import Utility.Metered
 import Utility.Percentage
-import Utility.QuickCheck
 import Utility.PID
 import Annex.LockPool
 import Logs.TimeStamp
@@ -290,17 +289,6 @@
 	</> "failed"
 	</> showLcDirection direction
 	</> filter (/= '/') (fromUUID u)
-
-instance Arbitrary TransferInfo where
-	arbitrary = TransferInfo
-		<$> arbitrary
-		<*> arbitrary
-		<*> pure Nothing -- cannot generate a ThreadID
-		<*> pure Nothing -- remote not needed
-		<*> arbitrary
-		-- associated file cannot be empty (but can be Nothing)
-		<*> arbitrary `suchThat` (/= Just "")
-		<*> arbitrary
 
 prop_read_write_transferinfo :: TransferInfo -> Bool
 prop_read_write_transferinfo info
diff --git a/Messages/Concurrent.hs b/Messages/Concurrent.hs
--- a/Messages/Concurrent.hs
+++ b/Messages/Concurrent.hs
@@ -32,10 +32,12 @@
  - instead.
  -}
 concurrentMessage :: OutputType -> Bool -> String -> Annex () -> Annex ()
-concurrentMessage o iserror msg fallback 
 #ifdef WITH_CONCURRENTOUTPUT
+concurrentMessage o iserror msg fallback 
 	| concurrentOutputEnabled o =
 		go =<< consoleRegion <$> Annex.getState Annex.output
+#else
+concurrentMessage _o _iserror _msg fallback 
 #endif
 	| otherwise = fallback
 #ifdef WITH_CONCURRENTOUTPUT
@@ -67,8 +69,8 @@
  - complete.
  -}
 inOwnConsoleRegion :: OutputType -> Annex a -> Annex a
-inOwnConsoleRegion o a
 #ifdef WITH_CONCURRENTOUTPUT
+inOwnConsoleRegion o a
 	| concurrentOutputEnabled o = do
 		r <- mkregion
 		setregion (Just r)
@@ -82,6 +84,8 @@
 			Right ret -> do
 				rmregion r
 				return ret
+#else
+inOwnConsoleRegion _o a
 #endif
 	| otherwise = a
 #ifdef WITH_CONCURRENTOUTPUT
diff --git a/Messages/Progress.hs b/Messages/Progress.hs
--- a/Messages/Progress.hs
+++ b/Messages/Progress.hs
@@ -45,8 +45,8 @@
 			maybe noop (\m -> m n) combinemeterupdate
 		liftIO $ clearMeter stdout meter
 		return r
-	go size o@(ConcurrentOutput {})
 #if WITH_CONCURRENTOUTPUT
+	go size o@(ConcurrentOutput {})
 		| concurrentOutputEnabled o = withProgressRegion $ \r -> do
 			(progress, meter) <- mkmeter size
 			a $ \n -> liftIO $ do
@@ -54,6 +54,8 @@
 				s <- renderMeter meter
 				Regions.setConsoleRegion r ("\n" ++ s)
 				maybe noop (\m -> m n) combinemeterupdate
+#else
+	go _size _o
 #endif
 		| otherwise = nometer
 
diff --git a/Remote/External.hs b/Remote/External.hs
--- a/Remote/External.hs
+++ b/Remote/External.hs
@@ -21,6 +21,7 @@
 import Remote.Helper.ReadOnly
 import Remote.Helper.Messages
 import Utility.Metered
+import Utility.Shell
 import Messages.Progress
 import Types.Transfer
 import Logs.PreferredContent.Raw
@@ -374,7 +375,13 @@
 	errrelayer <- mkStderrRelayer
 	g <- Annex.gitRepo
 	liftIO $ do
-		p <- propgit g cmdp
+		(cmd, ps) <- findShellCommand basecmd
+		let basep = (proc cmd (toCommand ps))
+			{ std_in = CreatePipe
+			, std_out = CreatePipe
+			, std_err = CreatePipe
+			}
+		p <- propgit g basep
 		(Just hin, Just hout, Just herr, pid) <- 
 			createProcess p `catchIO` runerr
 		fileEncoding hin
@@ -391,24 +398,20 @@
 			, externalPrepared = Unprepared
 			}
   where
-	cmd = externalRemoteProgram externaltype
-	cmdp = (proc cmd [])
-		{ std_in = CreatePipe
-		, std_out = CreatePipe
-		, std_err = CreatePipe
-		}
+	basecmd = externalRemoteProgram externaltype
+
 	propgit g p = do
 		environ <- propGitEnv g
 		return $ p { env = Just environ }
 
-	runerr _ = error ("Cannot run " ++ cmd ++ " -- Make sure it's in your PATH and is executable.")
+	runerr _ = error ("Cannot run " ++ basecmd ++ " -- Make sure it's in your PATH and is executable.")
 
 	checkearlytermination Nothing = noop
-	checkearlytermination (Just exitcode) = ifM (inPath cmd)
-		( error $ unwords [ "failed to run", cmd, "(" ++ show exitcode ++ ")" ]
+	checkearlytermination (Just exitcode) = ifM (inPath basecmd)
+		( error $ unwords [ "failed to run", basecmd, "(" ++ show exitcode ++ ")" ]
 		, do
 			path <- intercalate ":" <$> getSearchPath
-			error $ cmd ++ " is not installed in PATH (" ++ path ++ ")"
+			error $ basecmd ++ " is not installed in PATH (" ++ path ++ ")"
 		)
 
 stopExternal :: External -> Annex ()
diff --git a/Test.hs b/Test.hs
--- a/Test.hs
+++ b/Test.hs
@@ -51,7 +51,6 @@
 import qualified Git.FilePath
 import qualified Annex.Locations
 import qualified Types.KeySource
-import qualified Types.Remote
 import qualified Types.Backend
 import qualified Types.TrustLevel
 import qualified Types
@@ -102,6 +101,7 @@
 import qualified Remote.Helper.Encryptable
 import qualified Types.Crypto
 import qualified Utility.Gpg
+import qualified Types.Remote
 #endif
 
 optParser :: Parser TestOptions
diff --git a/Types/Command.hs b/Types/Command.hs
--- a/Types/Command.hs
+++ b/Types/Command.hs
@@ -1,6 +1,6 @@
 {- git-annex command data types
  -
- - Copyright 2010-2015 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2016 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU GPL version 3 or higher.
  -}
@@ -11,6 +11,7 @@
 import Options.Applicative.Types (Parser)
 
 import Types
+import Types.DeferredParse
 
 {- A command runs in these stages.
  -
@@ -46,6 +47,7 @@
 	, cmdsection :: CommandSection
 	, cmddesc :: String          -- description of command for usage
 	, cmdparser :: CommandParser -- command line parser
+	, cmdglobaloptions :: [GlobalOption] -- additional global options
 	, cmdnorepo :: Maybe (Parser (IO ())) -- used when not in a repo
 	}
 
diff --git a/Types/Transfer.hs b/Types/Transfer.hs
--- a/Types/Transfer.hs
+++ b/Types/Transfer.hs
@@ -9,9 +9,12 @@
 
 import Types
 import Utility.PID
+import Utility.QuickCheck
 
 import Data.Time.Clock.POSIX
 import Control.Concurrent
+import Control.Applicative
+import Prelude
 
 {- Enough information to uniquely identify a transfer, used as the filename
  - of the transfer information file. -}
@@ -45,3 +48,13 @@
 data Direction = Upload | Download
 	deriving (Eq, Ord, Read, Show)
 
+instance Arbitrary TransferInfo where
+	arbitrary = TransferInfo
+		<$> arbitrary
+		<*> arbitrary
+		<*> pure Nothing -- cannot generate a ThreadID
+		<*> pure Nothing -- remote not needed
+		<*> arbitrary
+		-- associated file cannot be empty (but can be Nothing)
+		<*> arbitrary `suchThat` (/= Just "")
+		<*> arbitrary
diff --git a/Utility/Shell.hs b/Utility/Shell.hs
--- a/Utility/Shell.hs
+++ b/Utility/Shell.hs
@@ -9,6 +9,19 @@
 
 module Utility.Shell where
 
+import Utility.SafeCommand
+#ifdef mingw32_HOST_OS
+import Utility.Path
+import Utility.FileSystemEncoding
+import Utility.Exception
+import Utility.PartialPrelude
+#endif
+
+#ifdef mingw32_HOST_OS
+import System.IO
+import System.FilePath
+#endif
+
 shellPath_portable :: FilePath
 shellPath_portable = "/bin/sh"
 
@@ -24,3 +37,32 @@
 
 shebang_local :: String
 shebang_local = "#!" ++ shellPath_local
+
+-- | On Windows, shebang is not handled by the kernel, so to support
+-- shell scripts etc, have to look at the program being run and
+-- parse it for shebang.
+--
+-- This has no effect on Unix.
+findShellCommand :: FilePath -> IO (FilePath, [CommandParam])
+findShellCommand f = do
+#ifndef mingw32_HOST_OS
+	defcmd
+#else
+	l <- catchDefaultIO Nothing $ withFile f ReadMode $ \h -> do
+		fileEncoding h
+		headMaybe . lines <$> hGetContents h
+	case l of
+		Just ('#':'!':rest) -> case words rest of
+			[] -> defcmd
+			(c:ps) -> do
+				let ps' = map Param ps ++ [File f]
+				-- If the command is not inPath,
+				-- take the base of it, and run eg "sh"
+				-- which in some cases on windows will work
+				-- despite it not being inPath.
+				ok <- inPath c
+				return (if ok then c else takeFileName c, ps')
+		_ -> defcmd
+#endif
+  where
+	defcmd = return (f, [])
diff --git a/Utility/WebApp.hs b/Utility/WebApp.hs
--- a/Utility/WebApp.hs
+++ b/Utility/WebApp.hs
@@ -127,12 +127,12 @@
 	go' :: Int -> AddrInfo -> IO Socket
 	go' 0 _ = error "unable to bind to local socket"
 	go' n addr = do
-		r <- tryIO $ bracketOnError (open addr) sClose (useaddr addr)
+		r <- tryIO $ bracketOnError (open addr) close (useaddr addr)
 		either (const $ go' (pred n) addr) return r
 	open addr = socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
 	useaddr addr sock = do
 		preparesocket sock
-		bindSocket sock (addrAddress addr)
+		bind sock (addrAddress addr)
 		use sock
 #endif
 	preparesocket sock = setSocketOption sock ReuseAddr 1
diff --git a/doc/git-annex-get.mdwn b/doc/git-annex-get.mdwn
--- a/doc/git-annex-get.mdwn
+++ b/doc/git-annex-get.mdwn
@@ -23,7 +23,8 @@
 * `--from=remote`
 
   Normally git-annex will choose which remotes to get the content
-  from. Use this option to specify which remote to use. 
+  from, preferring less expensive remotes. Use this option to specify
+  which remote to use. 
   
   Any files that are not available on the remote will be silently skipped.
 
diff --git a/doc/git-annex-smudge.mdwn b/doc/git-annex-smudge.mdwn
--- a/doc/git-annex-smudge.mdwn
+++ b/doc/git-annex-smudge.mdwn
@@ -25,7 +25,7 @@
 	        clean = git-annex smudge --clean %f
 
 To make git use that filter driver, it needs to be configured in
-the .gitattributes file or in `.git/config/attributes`. The latter
+the `.gitattributes` file or in `.git/info/attributes`. The latter
 is normally configured when a repository is initialized, with the following
 contents:
 
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: 6.20160808
+Version: 6.20160907
 Cabal-Version: >= 1.8
 License: GPL-3
 Maintainer: Joey Hess <id@joeyh.name>
@@ -329,15 +329,42 @@
    stm (>= 2.3),
    mtl (>= 2),
    uuid (>= 1.2.6),
-   process, data-default, case-insensitive, random, dlist,
-   unix-compat, SafeSemaphore, async, directory, filepath, IfElse,
-   MissingH, hslogger, monad-logger,
-   utf8-string, bytestring, text, sandi,
-   monad-control, transformers,
-   bloomfilter, edit-distance,
-   resourcet, http-conduit (<2.2.0), http-client, http-types,
-   time, old-locale,
-   esqueleto, persistent-sqlite, persistent (<2.5), persistent-template,
+   process,
+   data-default,
+   case-insensitive,
+   random,
+   dlist,
+   unix-compat,
+   SafeSemaphore,
+   async,
+   directory,
+   filepath,
+   IfElse,
+   MissingH,
+   hslogger,
+   monad-logger,
+   utf8-string,
+   bytestring,
+   text,
+   sandi,
+   monad-control,
+   transformers,
+   bloomfilter,
+   edit-distance,
+   resourcet,
+   http-client,
+   http-types,
+   -- Old version needed due to https://github.com/aristidb/aws/issues/206
+   http-conduit (<2.2.0),
+   time,
+   old-locale,
+   esqueleto,
+   persistent-sqlite, 
+   -- Old version needed due to
+   -- https://github.com/prowdsponsor/esqueleto/issues/137
+   -- and also temporarily to make ghc 8 builds work
+   persistent (< 2.5),
+   persistent-template,
    aeson,
    unordered-containers,
    feed,
@@ -438,8 +465,11 @@
      path-pieces (>= 0.1.4),
      warp (>= 3.0.0.5),
      warp-tls (>= 1.4),
-     wai, wai-extra,
-     blaze-builder, crypto-api, clientsession,
+     wai,
+     wai-extra,
+     blaze-builder,
+     crypto-api,
+     clientsession,
      template-haskell,
      shakespeare (>= 2.0.0),
      securemem,
