diff --git a/Annex/Direct.hs b/Annex/Direct.hs
--- a/Annex/Direct.hs
+++ b/Annex/Direct.hs
@@ -61,7 +61,10 @@
 		shakey <- catKey sha
 		mstat <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus file
 		mcache <- liftIO $ maybe (pure Nothing) (toInodeCache delta file) mstat
-		filekey <- isAnnexLink file
+		filekey <- isAnnexLink file >>= \case
+			Just k -> return (Just k)
+			-- v7 unlocked pointer file
+			Nothing -> liftIO (isPointerFile file)
 		case (shakey, filekey, mstat, mcache) of
 			(_, Just key, _, _)
 				| shakey == filekey -> noop
diff --git a/Annex/FileMatcher.hs b/Annex/FileMatcher.hs
--- a/Annex/FileMatcher.hs
+++ b/Annex/FileMatcher.hs
@@ -60,7 +60,7 @@
 	| isEmpty matcher = notconfigured
 	| otherwise = case (mkey, afile) of
 		(_, AssociatedFile (Just file)) -> go =<< fileMatchInfo file
-		(Just key, _) -> go (MatchingKey key)
+		(Just key, _) -> go (MatchingKey key afile)
 		_ -> d
   where
 	go mi = matchMrun matcher $ \a -> a notpresent mi
diff --git a/Annex/WorkTree.hs b/Annex/WorkTree.hs
--- a/Annex/WorkTree.hs
+++ b/Annex/WorkTree.hs
@@ -14,6 +14,8 @@
 import Annex.Content
 import Annex.ReplaceFile
 import Annex.CurrentBranch
+import Annex.InodeSentinal
+import Utility.InodeCache
 import Config
 import Git.FilePath
 import qualified Git.Ref
@@ -84,9 +86,12 @@
 		whenM (inAnnex k) $ do
 			f <- fromRepo $ fromTopFilePath tf
 			destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f
-			replaceFile f $ \tmp ->
+			ic <- replaceFile f $ \tmp ->
 				linkFromAnnex k tmp destmode >>= \case
-					LinkAnnexOk -> return ()
-					LinkAnnexNoop -> return ()
-					LinkAnnexFailed -> liftIO $
+					LinkAnnexOk -> 
+						withTSDelta (liftIO . genInodeCache tmp)
+					LinkAnnexNoop -> return Nothing
+					LinkAnnexFailed -> liftIO $ do
 						writePointerFile tmp k destmode
+						return Nothing
+			maybe noop (restagePointerFile (Restage True) f) ic
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,29 @@
+git-annex (7.20181211) upstream; urgency=medium
+
+  * S3: Improve diagnostics when a remote is configured with exporttree and
+    versioning, but no S3 version id has been recorded for a key.
+  * findref: Support file matching options: --include, --exclude,
+    --want-get, --want-drop, --largerthan, --smallerthan, --accessedwithin
+  * Commands supporting --branch now apply file matching options --include,
+    --exclude, --want-get, --want-drop to filenames from the branch.
+    Previously, combining --branch with those would fail to match anything.
+  * add, import, findref: Support --time-limit.
+  * Add --branch option to git-annex find and mildly deprecate findref in
+    favor of it.
+  * webdav: When initializing, avoid trying to make a directory at the top of
+    the webdav server, which could never accomplish anything and failed on
+    nextcloud servers. (Reversion introduced in version 6.20170925.)
+  * Fix a case where upgrade to v7 caused git to think that unlocked files
+    were modified.
+  * Fix bug upgrading from direct mode to v7: when files in the repository
+    were already committed as v7 unlocked files elsewhere, and the
+    content was present in the direct mode repository, the annexed files
+    got their full content checked into git.
+  * Fix bug that caused v7 unlocked files in a direct mode repository
+    to get locked when committing.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 11 Dec 2018 16:33:10 -0400
+
 git-annex (7.20181205) upstream; urgency=medium
 
   * Make bittorrent special remote work w/o btshowmetainfo installed
diff --git a/CmdLine/GitAnnex/Options.hs b/CmdLine/GitAnnex/Options.hs
--- a/CmdLine/GitAnnex/Options.hs
+++ b/CmdLine/GitAnnex/Options.hs
@@ -174,10 +174,7 @@
 
 parseKeyOptions :: Parser KeyOptions
 parseKeyOptions = parseAllOption
-	<|> WantBranchKeys <$> some (option (str >>= pure . Ref)
-		( long "branch" <> metavar paramRef
-		<> help "operate on files in the specified branch or treeish"
-		))
+	<|> parseBranchKeysOption
 	<|> flag' WantUnusedKeys
 		( long "unused" <> short 'U'
 		<> help "operate on files found by last run of git-annex unused"
@@ -187,6 +184,13 @@
 		<> help "operate on specified key"
 		))
 
+parseBranchKeysOption :: Parser KeyOptions
+parseBranchKeysOption =
+	WantBranchKeys <$> some (option (str >>= pure . Ref)
+		( long "branch" <> metavar paramRef
+		<> help "operate on files in the specified branch or treeish"
+		))
+
 parseFailedTransfersOption :: Parser KeyOptions
 parseFailedTransfersOption = flag' WantFailedTransfers
 	( long "failed"
@@ -211,18 +215,18 @@
 -- Options to match properties of annexed files.
 annexedMatchingOptions :: [GlobalOption]
 annexedMatchingOptions = concat
-	[ nonWorkTreeMatchingOptions'
+	[ keyMatchingOptions'
 	, fileMatchingOptions'
 	, combiningOptions
 	, timeLimitOption
 	]
 
--- Matching options that don't need to examine work tree files.
-nonWorkTreeMatchingOptions :: [GlobalOption]
-nonWorkTreeMatchingOptions = nonWorkTreeMatchingOptions' ++ combiningOptions
+-- Matching options that can operate on keys as well as files.
+keyMatchingOptions :: [GlobalOption]
+keyMatchingOptions = keyMatchingOptions' ++ combiningOptions ++ timeLimitOption
 
-nonWorkTreeMatchingOptions' :: [GlobalOption]
-nonWorkTreeMatchingOptions' = 
+keyMatchingOptions' :: [GlobalOption]
+keyMatchingOptions' = 
 	[ globalSetter Limit.addIn $ strOption
 		( long "in" <> short 'i' <> metavar paramRemote
 		<> help "match files present in a remote"
@@ -285,7 +289,7 @@
 
 -- Options to match files which may not yet be annexed.
 fileMatchingOptions :: [GlobalOption]
-fileMatchingOptions = fileMatchingOptions' ++ combiningOptions
+fileMatchingOptions = fileMatchingOptions' ++ combiningOptions ++ timeLimitOption
 
 fileMatchingOptions' :: [GlobalOption]
 fileMatchingOptions' =
diff --git a/CmdLine/Seek.hs b/CmdLine/Seek.hs
--- a/CmdLine/Seek.hs
+++ b/CmdLine/Seek.hs
@@ -24,6 +24,7 @@
 import CmdLine.GitAnnex.Options
 import Logs.Location
 import Logs.Unused
+import Types.ActionItem
 import Types.Transfer
 import Logs.Transfer
 import Remote.List
@@ -78,20 +79,6 @@
 	go fs = seekActions $ prepFiltered a $
 		return $ concat $ segmentPaths (map (\(WorkTreeItem f) -> f) l) fs
 
-withFilesInRefs :: ((FilePath, Key) -> CommandSeek) -> [Git.Ref] -> CommandSeek
-withFilesInRefs a = mapM_ go
-  where
-	go r = do	
-		matcher <- Limit.getMatcher
-		(l, cleanup) <- inRepo $ LsTree.lsTree r
-		forM_ l $ \i -> do
-			let f = getTopFilePath $ LsTree.file i
-			catKey (LsTree.sha i) >>= \case
-				Nothing -> noop
-				Just k -> whenM (matcher $ MatchingKey k) $
-					a (f, k)
-		liftIO $ void cleanup
-
 withPathContents :: ((FilePath, FilePath) -> CommandSeek) -> CmdParams -> CommandSeek
 withPathContents a params = do
 	matcher <- Limit.getMatcher
@@ -197,8 +184,12 @@
   where
 	mkkeyaction = do
 		matcher <- Limit.getMatcher
-		return $ \v ->
-			whenM (matcher $ MatchingKey $ fst v) $
+		return $ \v@(k, ai) ->
+			let i = case ai of
+				ActionItemBranchFilePath (BranchFilePath _ topf) ->
+					MatchingKey k (AssociatedFile $ Just $ getTopFilePath topf)
+				_ -> MatchingKey k (AssociatedFile Nothing)
+			in whenM (matcher i) $
 				keyaction v
 
 withKeyOptions' 
diff --git a/Command/Find.hs b/Command/Find.hs
--- a/Command/Find.hs
+++ b/Command/Find.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2010-2012 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2018 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU GPL version 3 or higher.
  -}
@@ -14,6 +14,8 @@
 import Annex.Content
 import Limit
 import Types.Key
+import Types.ActionItem
+import Git.FilePath
 import qualified Utility.Format
 import Utility.DataUnits
 
@@ -28,6 +30,7 @@
 data FindOptions = FindOptions
 	{ findThese :: CmdParams
 	, formatOption :: Maybe Utility.Format.Format
+	, keyOptions :: Maybe KeyOptions
 	, batchOption :: BatchMode
 	}
 
@@ -35,6 +38,7 @@
 optParser desc = FindOptions
 	<$> cmdParams desc
 	<*> optional parseFormatOption
+	<*> optional parseBranchKeysOption
 	<*> parseBatchOption
 
 parseFormatOption :: Parser Utility.Format.Format
@@ -50,7 +54,9 @@
 
 seek :: FindOptions -> CommandSeek
 seek o = case batchOption o of
-	NoBatch -> withFilesInGit (commandAction . go)
+	NoBatch -> withKeyOptions (keyOptions o) False
+		(commandAction . startKeys o)
+		(withFilesInGit (commandAction . go))
 		=<< workTreeItems (findThese o)
 	Batch fmt -> batchFilesMatching fmt go
   where
@@ -65,6 +71,11 @@
 		next $ next $ return True
 	, stop
 	)
+
+startKeys :: FindOptions -> (Key, ActionItem) -> CommandStart
+startKeys o (key, ActionItemBranchFilePath (BranchFilePath _ topf)) = 
+	start o (getTopFilePath topf) key
+startKeys _ _ = stop
 
 showFormatted :: Maybe Utility.Format.Format -> String -> [(String, String)] -> Annex ()
 showFormatted format unformatted vars =
diff --git a/Command/FindRef.hs b/Command/FindRef.hs
--- a/Command/FindRef.hs
+++ b/Command/FindRef.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2014 Joey Hess <id@joeyh.name>
+ - Copyright 2014-2018 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU GPL version 3 or higher.
  -}
@@ -12,11 +12,16 @@
 import qualified Git
 
 cmd :: Command
-cmd = withGlobalOptions [nonWorkTreeMatchingOptions] $ Find.mkCommand $ 
+cmd = withGlobalOptions [annexedMatchingOptions] $ Find.mkCommand $ 
 	command "findref" SectionPlumbing
-		"lists files in a git ref"
+		"lists files in a git ref (deprecated)"
 		paramRef (seek <$$> Find.optParser)
 
 seek :: Find.FindOptions -> CommandSeek
-seek o = (commandAction . uncurry (Find.start o))
-	`withFilesInRefs` (map Git.Ref $ Find.findThese o)
+seek o = Find.seek o'
+  where
+	o' = o 
+		{ Find.keyOptions = Just $ WantBranchKeys $
+			map Git.Ref (Find.findThese o)
+		, Find.findThese = []
+		}
diff --git a/Creds.hs b/Creds.hs
--- a/Creds.hs
+++ b/Creds.hs
@@ -11,7 +11,7 @@
 	setRemoteCredPair,
 	getRemoteCredPair,
 	getRemoteCredPairFor,
-	warnMissingCredPairFor,
+	missingCredPairFor,
 	getEnvCredPair,
 	writeCreds,
 	readCreds,
@@ -118,12 +118,12 @@
 getRemoteCredPairFor this c gc storage = go =<< getRemoteCredPair c gc storage
   where
 	go Nothing = do
-		warnMissingCredPairFor this storage
+		warning $ missingCredPairFor this storage
 		return Nothing
 	go (Just credpair) = return $ Just credpair
 
-warnMissingCredPairFor :: String -> CredPairStorage -> Annex ()
-warnMissingCredPairFor this storage = warning $ unwords
+missingCredPairFor :: String -> CredPairStorage -> String
+missingCredPairFor this storage = unwords
 	[ "Set both", loginvar
 	, "and", passwordvar
 	, "to use", this
diff --git a/Limit.hs b/Limit.hs
--- a/Limit.hs
+++ b/Limit.hs
@@ -94,16 +94,17 @@
 matchGlobFile glob = go
   where
 	cglob = compileGlob glob CaseSensative -- memoized
-	go (MatchingKey _) = pure False
 	go (MatchingFile fi) = pure $ matchGlob cglob (matchFile fi)
 	go (MatchingInfo af _ _ _) = matchGlob cglob <$> getInfo af
+	go (MatchingKey _ (AssociatedFile Nothing)) = pure False
+	go (MatchingKey _ (AssociatedFile (Just af))) = pure $ matchGlob cglob af
 
 #ifdef WITH_MAGICMIME
 matchMagic :: Maybe Magic -> MkLimit Annex
 matchMagic (Just magic) glob = Right $ const go
   where
  	cglob = compileGlob glob CaseSensative -- memoized
-	go (MatchingKey _) = pure False
+	go (MatchingKey _ _) = pure False
 	go (MatchingFile fi) = liftIO $ catchBoolIO $
 		matchGlob cglob <$> magicFile magic (currFile fi)
 	go (MatchingInfo _ _ _ mimeval) = matchGlob cglob <$> getInfo mimeval
@@ -152,7 +153,8 @@
 limitInDir dir = const go
   where
 	go (MatchingFile fi) = checkf $ matchFile fi
-	go (MatchingKey _) = return False
+	go (MatchingKey _ (AssociatedFile Nothing)) = return False
+	go (MatchingKey _ (AssociatedFile (Just af))) = checkf af
 	go (MatchingInfo af _ _ _) = checkf =<< getInfo af
 	checkf = return . elem dir . splitPath . takeDirectory
 
@@ -200,7 +202,7 @@
 			then approxNumCopies
 			else case mi of
 				MatchingFile fi -> getGlobalFileNumCopies $ matchFile fi
-				MatchingKey _ -> approxNumCopies
+				MatchingKey _ _ -> approxNumCopies
 				MatchingInfo _ _ _ _ -> approxNumCopies
 		us <- filter (`S.notMember` notpresent)
 			<$> (trustExclude UnTrusted =<< Remote.keyLocations key)
@@ -214,7 +216,7 @@
  -}
 limitUnused :: MatchFiles Annex
 limitUnused _ (MatchingFile _) = return False
-limitUnused _ (MatchingKey k) = S.member k <$> unusedKeys
+limitUnused _ (MatchingKey k _) = S.member k <$> unusedKeys
 limitUnused _ (MatchingInfo _ ak _ _) = do
 	k <- getInfo ak
 	S.member k <$> unusedKeys
@@ -277,7 +279,7 @@
 	Just sz -> Right $ go sz
   where
 	go sz _ (MatchingFile fi) = lookupFileKey fi >>= check fi sz
-	go sz _ (MatchingKey key) = checkkey sz key
+	go sz _ (MatchingKey key _) = checkkey sz key
 	go sz _ (MatchingInfo _ _ as _) =
 		getInfo as >>= \sz' -> return (Just sz' `vs` Just sz)
 	checkkey sz key = return $ keySize key `vs` Just sz
@@ -329,5 +331,5 @@
 
 checkKey :: (Key -> Annex Bool) -> MatchInfo -> Annex Bool
 checkKey a (MatchingFile fi) = lookupFileKey fi >>= maybe (return False) a
-checkKey a (MatchingKey k) = a k
+checkKey a (MatchingKey k _) = a k
 checkKey a (MatchingInfo _ ak _ _) = a =<< getInfo ak
diff --git a/Limit/Wanted.hs b/Limit/Wanted.hs
--- a/Limit/Wanted.hs
+++ b/Limit/Wanted.hs
@@ -22,5 +22,5 @@
 
 checkWant :: (AssociatedFile -> Annex Bool) -> MatchInfo -> Annex Bool
 checkWant a (MatchingFile fi) = a (AssociatedFile (Just $ matchFile fi))
-checkWant _ (MatchingKey _) = return False
+checkWant a (MatchingKey _ af) = a af
 checkWant _ (MatchingInfo {}) = return False
diff --git a/Remote/S3.hs b/Remote/S3.hs
--- a/Remote/S3.hs
+++ b/Remote/S3.hs
@@ -259,15 +259,18 @@
  - out to the file. Would be better to implement a byteRetriever, but
  - that is difficult. -}
 retrieve :: Remote -> RemoteConfig -> S3Info -> Maybe S3Handle -> Retriever
-retrieve r _ info (Just h) = fileRetriever $ \f k p -> do
-	loc <- eitherS3VersionID info (uuid r) k (T.pack $ bucketObject info k)
-	retrieveHelper info h loc f p
+retrieve r c info (Just h) = fileRetriever $ \f k p ->
+	eitherS3VersionID info (uuid r) c k (T.pack $ bucketObject info k) >>= \case
+		Left failreason -> do
+			warning failreason
+			giveup "cannot download content"
+		Right loc -> retrieveHelper info h loc f p
 retrieve r c info Nothing = fileRetriever $ \f k p ->
-	getPublicWebUrls (uuid r) info c k >>= \case
-		[] -> do
-			needS3Creds (uuid r)
-			giveup "No S3 credentials configured"
-		us -> unlessM (downloadUrl k p us f) $
+	getPublicWebUrls' (uuid r) info c k >>= \case
+		Left failreason -> do
+			warning failreason
+			giveup "cannot download content"
+		Right us -> unlessM (downloadUrl k p us f) $
 			giveup "failed to download content"
 
 retrieveHelper :: S3Info -> S3Handle -> (Either S3.Object S3VersionID) -> FilePath -> MeterUpdate -> Annex ()
@@ -292,16 +295,19 @@
 	return $ either (const False) (const True) res
 
 checkKey :: Remote -> RemoteConfig -> S3Info -> Maybe S3Handle -> CheckPresent
-checkKey r _ info (Just h) k = do
+checkKey r c info (Just h) k = do
 	showChecking r
-	loc <- eitherS3VersionID info (uuid r) k (T.pack $ bucketObject info k)
-	checkKeyHelper info h loc
+	eitherS3VersionID info (uuid r) c k (T.pack $ bucketObject info k) >>= \case
+		Left failreason -> do
+			warning failreason
+			giveup "cannot check content"
+		Right loc -> checkKeyHelper info h loc
 checkKey r c info Nothing k = 
-	getPublicWebUrls (uuid r) info c k >>= \case
-		[] -> do
-			needS3Creds (uuid r)
-			giveup "No S3 credentials configured"
-		us -> do
+	getPublicWebUrls' (uuid r) info c k >>= \case
+		Left failreason -> do
+			warning failreason
+			giveup "cannot check content"
+		Right us -> do
 			showChecking r
 			let check u = withUrlOptions $ 
 				liftIO . checkBoth u (keySize k)
@@ -347,7 +353,7 @@
 			>>= setS3VersionID info u k
 		return True
 storeExportS3 u _ Nothing _ _ _ _ = do
-	needS3Creds u
+	warning $ needS3Creds u
 	return False
 
 retrieveExportS3 :: UUID -> S3Info -> Maybe S3Handle -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex Bool
@@ -360,7 +366,7 @@
 			return True
 		Nothing -> case getPublicUrlMaker info of
 			Nothing -> do
-				needS3Creds u
+				warning $ needS3Creds u
 				return False
 			Just geturl -> Url.withUrlOptions $ 
 				liftIO . Url.download p (geturl exporturl) f
@@ -375,7 +381,7 @@
 			S3.DeleteObject (T.pack $ bucketExportLocation info loc) (bucket info)
 		return $ either (const False) (const True) res
 removeExportS3 u _ Nothing _ _ = do
-	needS3Creds u
+	warning $ needS3Creds u
 	return False
 
 checkPresentExportS3 :: UUID -> S3Info -> Maybe S3Handle -> Key -> ExportLocation -> Annex Bool
@@ -383,7 +389,7 @@
 	checkKeyHelper info h (Left (T.pack $ bucketExportLocation info loc))
 checkPresentExportS3 u info Nothing k loc = case getPublicUrlMaker info of
 	Nothing -> do
-		needS3Creds u
+		warning $ needS3Creds u
 		giveup "No S3 credentials configured"
 	Just geturl -> withUrlOptions $ liftIO . 
 		checkBoth (geturl $ bucketExportLocation info loc) (keySize k)
@@ -403,7 +409,7 @@
 	srcobject = T.pack $ bucketExportLocation info src
 	dstobject = T.pack $ bucketExportLocation info dest
 renameExportS3 u _ Nothing _ _ _ = do
-	needS3Creds u
+	warning $ needS3Creds u
 	return False
 
 {- Generate the bucket if it does not already exist, including creating the
@@ -523,7 +529,7 @@
 withS3Handle c gc u a = withS3HandleMaybe c gc u $ \mh -> case mh of
 	Just h -> a h
 	Nothing -> do
-		needS3Creds u
+		warning $ needS3Creds u
 		giveup "No S3 credentials configured"
 
 withS3HandleMaybe :: RemoteConfig -> RemoteGitConfig -> UUID -> (Maybe S3Handle -> Annex a) -> Annex a
@@ -542,8 +548,8 @@
   where
 	s3cfg = s3Configuration c
 
-needS3Creds :: UUID -> Annex ()
-needS3Creds u = warnMissingCredPairFor "S3" (AWS.creds u)
+needS3Creds :: UUID -> String
+needS3Creds u = missingCredPairFor "S3" (AWS.creds u)
 
 s3Configuration :: RemoteConfig -> S3.S3Configuration AWS.NormalQuery
 s3Configuration c = cfg
@@ -734,19 +740,28 @@
 	showstorageclass sc = show sc
 
 getPublicWebUrls :: UUID -> S3Info -> RemoteConfig -> Key -> Annex [URLString]
-getPublicWebUrls u info c k
-	| not (public info) = return []
+getPublicWebUrls u info c k = either (const []) id <$> getPublicWebUrls' u info c k
+
+getPublicWebUrls' :: UUID -> S3Info -> RemoteConfig -> Key -> Annex (Either String [URLString])
+getPublicWebUrls' u info c k
+	| not (public info) = return $ Left $ 
+		"S3 bucket does not allow public access; " ++ needS3Creds u
 	| exportTree c = if versioning info
 		then case publicurl info of
-			Just url -> getS3VersionIDPublicUrls (const $ genericPublicUrl url) info u k
+			Just url -> getversionid (const $ genericPublicUrl url)
 			Nothing -> case host info of
 				Just h | h == AWS.s3DefaultHost ->
-					getS3VersionIDPublicUrls awsPublicUrl info u k
-				_ -> return []
-		else return []
+					getversionid awsPublicUrl
+				_ -> return nopublicurl
+		else return (Left "exporttree used without versioning")
 	| otherwise = case getPublicUrlMaker info of
-		Just geturl -> return [geturl $ bucketObject info k]
-		Nothing -> return []
+		Just geturl -> return (Right [geturl $ bucketObject info k])
+		Nothing -> return nopublicurl
+  where
+	nopublicurl = Left "No publicurl is configured for this remote"
+	getversionid url = getS3VersionIDPublicUrls url info u k >>= \case
+		[] -> return (Left "Remote is configured to use versioning, but no S3 version ID is recorded for this key")
+		l -> return (Right l)
 
 getPublicUrlMaker :: S3Info -> Maybe (BucketObject -> URLString)
 getPublicUrlMaker info = case publicurl info of
@@ -813,14 +828,16 @@
 s3VersionField :: MetaField
 s3VersionField = mkMetaFieldUnchecked "V"
 
-eitherS3VersionID :: S3Info -> UUID -> Key -> S3.Object -> Annex (Either S3.Object S3VersionID)
-eitherS3VersionID info u k fallback
+eitherS3VersionID :: S3Info -> UUID -> RemoteConfig -> Key -> S3.Object -> Annex (Either String (Either S3.Object S3VersionID))
+eitherS3VersionID info u c k fallback
 	| versioning info = getS3VersionID u k >>= return . \case
-		[] -> Left fallback
+		[] -> if exportTree c
+			then Left "Remote is configured to use versioning, but no S3 version ID is recorded for this key"
+			else Right (Left fallback)
 		-- It's possible for a key to be stored multiple timees in
 		-- a bucket with different version IDs; only use one of them.
-		(v:_) -> Right v
-	| otherwise = return (Left fallback)
+		(v:_) -> Right (Right v)
+	| otherwise = return (Right (Left fallback))
 
 s3VersionIDPublicUrl :: (S3Info -> BucketObject -> URLString) -> S3Info -> S3VersionID -> URLString
 s3VersionIDPublicUrl mk info (S3VersionID obj vid) = mk info $ concat
diff --git a/Remote/WebDAV.hs b/Remote/WebDAV.hs
--- a/Remote/WebDAV.hs
+++ b/Remote/WebDAV.hs
@@ -274,7 +274,6 @@
 	test $ liftIO $ evalDAVT url $ do
 		prepDAV user pass
 		makeParentDirs
-		void $ mkColRecursive "/"
 		inLocation (tmpLocation "test") $ do
 			putContentM (Nothing, L8.fromString "test")
 			delContentM
diff --git a/Types/FileMatcher.hs b/Types/FileMatcher.hs
--- a/Types/FileMatcher.hs
+++ b/Types/FileMatcher.hs
@@ -8,7 +8,7 @@
 module Types.FileMatcher where
 
 import Types.UUID (UUID)
-import Types.Key (Key)
+import Types.Key (Key, AssociatedFile)
 import Utility.Matcher (Matcher, Token)
 import Utility.FileSize
 
@@ -18,7 +18,7 @@
 
 data MatchInfo
 	= MatchingFile FileInfo
-	| MatchingKey Key
+	| MatchingKey Key AssociatedFile
 	| MatchingInfo (OptInfo FilePath) (OptInfo Key) (OptInfo FileSize) (OptInfo MimeType)
 
 type MimeType = String
diff --git a/Upgrade/V5.hs b/Upgrade/V5.hs
--- a/Upgrade/V5.hs
+++ b/Upgrade/V5.hs
@@ -33,7 +33,6 @@
 upgrade automatic = do
 	unless automatic $
 		showAction "v5 to v6"
-	scanUnlockedFiles
 	whenM isDirect $ do
 		{- Direct mode makes the same tradeoff of using less disk
 		 - space, with less preservation of old versions of files
@@ -62,6 +61,7 @@
 		 - contents too, don't use git checkout to check out the
 		 - adjust branch. Instead, update HEAD manually. -}
 		inRepo $ setHeadRef b
+	scanUnlockedFiles
 	configureSmudgeFilter
 	-- Inode sentinal file was only used in direct mode and when
 	-- locking down files as they were added. In v6, it's used more
diff --git a/doc/git-annex-find.mdwn b/doc/git-annex-find.mdwn
--- a/doc/git-annex-find.mdwn
+++ b/doc/git-annex-find.mdwn
@@ -26,6 +26,10 @@
 
   To list annexed files whose content is not present, specify `--not --in=here`
 
+* `--branch=ref`
+
+  List files in the specified branch or treeish.
+
 * `--print0`
 
   Output filenames terminated with nulls, for use with `xargs -0`
diff --git a/doc/git-annex-findref.mdwn b/doc/git-annex-findref.mdwn
--- a/doc/git-annex-findref.mdwn
+++ b/doc/git-annex-findref.mdwn
@@ -1,6 +1,6 @@
 # NAME
 
-git-annex findref - lists files in a git ref
+git-annex findref - lists files in a git ref (deprecated)
 
 # SYNOPSIS
 
@@ -8,9 +8,9 @@
 
 # DESCRIPTION
 
-This is very similar to the `git-annex find` command, but instead of
-finding files in the current work tree, it finds files in the
-specified git ref.
+This is the same as `git annex find` with the --branch option, and you're
+encouraged to use that instead unless you need to support older versions of
+git-annex.
 
 # OPTIONS
 
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -660,7 +660,7 @@
 
 * `findref [ref]`
 
-  Lists files in a git ref.
+  Lists files in a git ref. (deprecated)
   
   See [[git-annex-findref]](1) for details.
 
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: 7.20181205
+Version: 7.20181211
 Cabal-Version: >= 1.8
 License: GPL-3
 Maintainer: Joey Hess <id@joeyh.name>
