summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Annex/Content.hs24
-rw-r--r--Annex/FileMatcher.hs22
-rw-r--r--Annex/Init.hs3
-rw-r--r--Annex/Version.hs17
-rw-r--r--CmdLine/GitAnnex.hs2
-rw-r--r--Command/Direct.hs6
-rw-r--r--Command/Smudge.hs109
-rw-r--r--Command/Version.hs3
-rw-r--r--Config.hs18
-rw-r--r--Git.hs8
-rw-r--r--Limit.hs30
-rw-r--r--Logs/PreferredContent.hs4
-rw-r--r--Upgrade.hs6
-rw-r--r--Upgrade/V1.hs4
-rw-r--r--Upgrade/V5.hs18
-rw-r--r--debian/changelog10
-rw-r--r--doc/direct_mode.mdwn7
-rw-r--r--doc/git-annex-direct.mdwn6
-rw-r--r--doc/git-annex-indirect.mdwn5
-rw-r--r--doc/git-annex-smudge.mdwn47
-rw-r--r--doc/git-annex.mdwn8
-rw-r--r--doc/todo/smudge.mdwn14
-rw-r--r--doc/upgrades.mdwn39
23 files changed, 361 insertions, 49 deletions
diff --git a/Annex/Content.hs b/Annex/Content.hs
index 289a4f1b3..73cb6ab01 100644
--- a/Annex/Content.hs
+++ b/Annex/Content.hs
@@ -24,6 +24,8 @@ module Annex.Content (
withTmp,
checkDiskSpace,
moveAnnex,
+ linkAnnex,
+ LinkAnnexResult(..),
sendAnnex,
prepSendAnnex,
removeAnnex,
@@ -470,6 +472,28 @@ moveAnnex key src = withObjectLoc key storeobject storedirect
alreadyhave = liftIO $ removeFile src
+{- Hard links a file into .git/annex/objects/, falling back to a copy
+ - if necessary.
+ -
+ - Does not lock down the hard linked object, so that the user can modify
+ - the source file. So, adding an object to the annex this way can
+ - prevent losing the content if the source file is deleted, but does not
+ - guard against modifications.
+ -}
+linkAnnex :: Key -> FilePath -> Annex LinkAnnexResult
+linkAnnex key src = do
+ dest <- calcRepo (gitAnnexLocation key)
+ ifM (liftIO $ doesFileExist dest)
+ ( return LinkAnnexNoop
+ , modifyContent dest $
+ ifM (liftIO $ createLinkOrCopy src dest)
+ ( return LinkAnnexOk
+ , return LinkAnnexFailed
+ )
+ )
+
+data LinkAnnexResult = LinkAnnexOk | LinkAnnexFailed | LinkAnnexNoop
+
{- Runs an action to transfer an object's content.
-
- In direct mode, it's possible for the file to change as it's being sent.
diff --git a/Annex/FileMatcher.hs b/Annex/FileMatcher.hs
index 8b0db60ad..a008198f3 100644
--- a/Annex/FileMatcher.hs
+++ b/Annex/FileMatcher.hs
@@ -14,7 +14,6 @@ import Limit
import Utility.Matcher
import Types.Group
import Logs.Group
-import Logs.Remote
import Annex.UUID
import qualified Annex
import Types.FileMatcher
@@ -53,8 +52,8 @@ parsedToMatcher parsed = case partitionEithers parsed of
([], vs) -> Right $ generate vs
(es, _) -> Left $ unwords $ map ("Parse failure: " ++) es
-exprParser :: FileMatcher Annex -> FileMatcher Annex -> GroupMap -> M.Map UUID RemoteConfig -> Maybe UUID -> String -> [Either String (Token (MatchFiles Annex))]
-exprParser matchstandard matchgroupwanted groupmap configmap mu expr =
+exprParser :: FileMatcher Annex -> FileMatcher Annex -> Annex GroupMap -> M.Map UUID RemoteConfig -> Maybe UUID -> String -> [Either String (Token (MatchFiles Annex))]
+exprParser matchstandard matchgroupwanted getgroupmap configmap mu expr =
map parse $ tokenizeMatcher expr
where
parse = parseToken
@@ -62,12 +61,12 @@ exprParser matchstandard matchgroupwanted groupmap configmap mu expr =
matchgroupwanted
(limitPresent mu)
(limitInDir preferreddir)
- groupmap
+ getgroupmap
preferreddir = fromMaybe "public" $
M.lookup "preferreddir" =<< (`M.lookup` configmap) =<< mu
-parseToken :: FileMatcher Annex -> FileMatcher Annex -> MkLimit Annex -> MkLimit Annex -> GroupMap -> String -> Either String (Token (MatchFiles Annex))
-parseToken matchstandard matchgroupwanted checkpresent checkpreferreddir groupmap t
+parseToken :: FileMatcher Annex -> FileMatcher Annex -> MkLimit Annex -> MkLimit Annex -> Annex GroupMap -> String -> Either String (Token (MatchFiles Annex))
+parseToken matchstandard matchgroupwanted checkpresent checkpreferreddir getgroupmap t
| t `elem` tokens = Right $ token t
| t == "standard" = call matchstandard
| t == "groupwanted" = call matchgroupwanted
@@ -86,7 +85,7 @@ parseToken matchstandard matchgroupwanted checkpresent checkpreferreddir groupma
, ("largerthan", limitSize (>))
, ("smallerthan", limitSize (<))
, ("metadata", limitMetaData)
- , ("inallgroup", limitInAllGroup groupmap)
+ , ("inallgroup", limitInAllGroup getgroupmap)
]
where
(k, v) = separate (== '=') t
@@ -109,9 +108,12 @@ largeFilesMatcher = go =<< annexLargeFiles <$> Annex.getGitConfig
where
go Nothing = return matchAll
go (Just expr) = do
- gm <- groupMap
- rc <- readRemoteLog
u <- getUUID
+ -- No need to read remote configs, that's only needed for
+ -- inpreferreddir, which is used in preferred content
+ -- expressions but does not make sense in the
+ -- annex.largefiles expression.
+ let emptyconfig = M.empty
either badexpr return $
- parsedToMatcher $ exprParser matchAll matchAll gm rc (Just u) expr
+ parsedToMatcher $ exprParser matchAll matchAll groupMap emptyconfig (Just u) expr
badexpr e = error $ "bad annex.largefiles configuration: " ++ e
diff --git a/Annex/Init.hs b/Annex/Init.hs
index 65e9aa474..b00e41218 100644
--- a/Annex/Init.hs
+++ b/Annex/Init.hs
@@ -85,7 +85,8 @@ initialize' = do
unlessM isBare $
hookWrite preCommitHook
setDifferences
- setVersion supportedVersion
+ setVersion currentVersion
+ configureSmudgeFilter
ifM (crippledFileSystem <&&> not <$> isBare)
( do
enableDirectMode
diff --git a/Annex/Version.hs b/Annex/Version.hs
index d08f994e9..f9b24d9c4 100644
--- a/Annex/Version.hs
+++ b/Annex/Version.hs
@@ -15,14 +15,17 @@ import qualified Annex
type Version = String
-supportedVersion :: Version
-supportedVersion = "5"
+currentVersion :: Version
+currentVersion = "6"
+
+supportedVersions :: [Version]
+supportedVersions = ["5", currentVersion]
upgradableVersions :: [Version]
#ifndef mingw32_HOST_OS
-upgradableVersions = ["0", "1", "2", "4"]
+upgradableVersions = ["0", "1", "2", "4", "5"]
#else
-upgradableVersions = ["2", "3", "4"]
+upgradableVersions = ["2", "3", "4", "5"]
#endif
autoUpgradeableVersions :: [Version]
@@ -34,6 +37,12 @@ versionField = annexConfig "version"
getVersion :: Annex (Maybe Version)
getVersion = annexVersion <$> Annex.getGitConfig
+versionSupportsDirectMode :: Annex Bool
+versionSupportsDirectMode = go <$> getVersion
+ where
+ go (Just "6") = False
+ go _ = True
+
setVersion :: Version -> Annex ()
setVersion = setConfig versionField
diff --git a/CmdLine/GitAnnex.hs b/CmdLine/GitAnnex.hs
index f585bff3e..ba7689f70 100644
--- a/CmdLine/GitAnnex.hs
+++ b/CmdLine/GitAnnex.hs
@@ -96,6 +96,7 @@ import qualified Command.Upgrade
import qualified Command.Forget
import qualified Command.Proxy
import qualified Command.DiffDriver
+import qualified Command.Smudge
import qualified Command.Undo
import qualified Command.Version
#ifdef WITH_ASSISTANT
@@ -201,6 +202,7 @@ cmds testoptparser testrunner =
, Command.Forget.cmd
, Command.Proxy.cmd
, Command.DiffDriver.cmd
+ , Command.Smudge.cmd
, Command.Undo.cmd
, Command.Version.cmd
#ifdef WITH_ASSISTANT
diff --git a/Command/Direct.hs b/Command/Direct.hs
index 162780dd5..9cfd258eb 100644
--- a/Command/Direct.hs
+++ b/Command/Direct.hs
@@ -14,6 +14,7 @@ import qualified Git.LsFiles
import qualified Git.Branch
import Config
import Annex.Direct
+import Annex.Version
cmd :: Command
cmd = notBareRepo $ noDaemonRunning $
@@ -24,7 +25,10 @@ seek :: CmdParams -> CommandSeek
seek = withNothing start
start :: CommandStart
-start = ifM isDirect ( stop , next perform )
+start = ifM versionSupportsDirectMode
+ ( ifM isDirect ( stop , next perform )
+ , error "Direct mode is not suppported by this repository version. Use git-annex unlock instead."
+ )
perform :: CommandPerform
perform = do
diff --git a/Command/Smudge.hs b/Command/Smudge.hs
new file mode 100644
index 000000000..70a318c2d
--- /dev/null
+++ b/Command/Smudge.hs
@@ -0,0 +1,109 @@
+{- git-annex command
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Command.Smudge where
+
+import Common.Annex
+import Command
+import Types.Key
+import Annex.Content
+import Annex.MetaData
+import Annex.FileMatcher
+import Types.KeySource
+import Backend
+import Logs.Location
+
+import qualified Data.ByteString.Lazy as B
+
+cmd :: Command
+cmd = noCommit $ noMessages $
+ command "smudge" SectionPlumbing
+ "git smudge filter"
+ paramFile (seek <$$> optParser)
+
+data SmudgeOptions = SmudgeOptions
+ { smudgeFile :: FilePath
+ , cleanOption :: Bool
+ }
+
+optParser :: CmdParamsDesc -> Parser SmudgeOptions
+optParser desc = SmudgeOptions
+ <$> argument str ( metavar desc )
+ <*> switch ( long "clean" <> help "clean filter" )
+
+seek :: SmudgeOptions -> CommandSeek
+seek o = commandAction $
+ (if cleanOption o then clean else smudge) (smudgeFile o)
+
+-- Smudge filter is fed git file content, and if it's a pointer to an
+-- available annex object, should output its content.
+smudge :: FilePath -> CommandStart
+smudge _file = do
+ liftIO $ fileEncoding stdin
+ s <- liftIO $ hGetContents stdin
+ case parsePointer s of
+ Nothing -> liftIO $ putStr s
+ Just k -> do
+ content <- calcRepo (gitAnnexLocation k)
+ liftIO $ maybe
+ (putStr s)
+ (B.hPut stdout)
+ =<< catchMaybeIO (B.readFile content)
+ stop
+
+-- Clean filter decides if a file should be stored in the annex, and
+-- outputs a pointer to its injested content.
+clean :: FilePath -> CommandStart
+clean file = do
+ ifM (shouldAnnex file)
+ ( do
+ k <- ingest file
+ liftIO $ emitPointer k
+ , liftIO cat
+ )
+ stop
+
+cat :: IO ()
+cat = B.hGetContents stdin >>= B.hPut stdout
+
+shouldAnnex :: FilePath -> Annex Bool
+shouldAnnex file = do
+ matcher <- largeFilesMatcher
+ checkFileMatcher matcher file
+
+ingest :: FilePath -> Annex Key
+ingest file = do
+ backend <- chooseBackend file
+ let source = KeySource
+ { keyFilename = file
+ , contentLocation = file
+ , inodeCache = Nothing
+ }
+ k <- fst . fromMaybe (error "failed to generate a key")
+ <$> genKey source backend
+ -- Hard link (or copy) file content to annex
+ -- to prevent it from being lost when git checks out
+ -- a branch not containing this file.
+ r <- linkAnnex k file
+ case r of
+ LinkAnnexFailed -> error "Problem adding file to the annex"
+ LinkAnnexOk -> logStatus k InfoPresent
+ LinkAnnexNoop -> noop
+ genMetaData k file
+ =<< liftIO (getFileStatus file)
+ return k
+
+emitPointer :: Key -> IO ()
+emitPointer = putStrLn . key2file
+
+parsePointer :: String -> Maybe Key
+parsePointer s
+ | length s' >= maxsz = Nothing -- too long to be a key pointer
+ | otherwise = headMaybe (lines s') >>= file2key
+ where
+ s' = take maxsz s
+ maxsz = 81920
diff --git a/Command/Version.hs b/Command/Version.hs
index 72bbe4064..c5a9fcef2 100644
--- a/Command/Version.hs
+++ b/Command/Version.hs
@@ -50,7 +50,8 @@ showVersion = do
liftIO $ do
showPackageVersion
vinfo "local repository version" $ fromMaybe "unknown" v
- vinfo "supported repository version" supportedVersion
+ vinfo "supported repository versions" $
+ unwords supportedVersions
vinfo "upgrade supported from repository versions" $
unwords upgradableVersions
diff --git a/Config.hs b/Config.hs
index 4af4f1284..f3833b17e 100644
--- a/Config.hs
+++ b/Config.hs
@@ -90,3 +90,21 @@ setCrippledFileSystem :: Bool -> Annex ()
setCrippledFileSystem b = do
setConfig (annexConfig "crippledfilesystem") (Git.Config.boolConfig b)
Annex.changeGitConfig $ \c -> c { annexCrippledFileSystem = b }
+
+configureSmudgeFilter :: Annex ()
+configureSmudgeFilter = do
+ setConfig (ConfigKey "filter.annex.smudge") "git-annex smudge %f"
+ setConfig (ConfigKey "filter.annex.clean") "git-annex smudge --clean %f"
+ lf <- Annex.fromRepo Git.attributesLocal
+ gf <- Annex.fromRepo Git.attributes
+ lfs <- readattr lf
+ gfs <- readattr gf
+ liftIO $ unless ("filter=annex" `isInfixOf` (lfs ++ gfs)) $ do
+ createDirectoryIfMissing True (takeDirectory lf)
+ writeFile lf (lfs ++ "\n" ++ stdattr)
+ where
+ readattr = liftIO . catchDefaultIO "" . readFileStrictAnyEncoding
+ stdattr = unlines
+ [ "* filter=annex"
+ , ".* !filter"
+ ]
diff --git a/Git.hs b/Git.hs
index 1bc789f85..6f7769c87 100644
--- a/Git.hs
+++ b/Git.hs
@@ -28,6 +28,7 @@ module Git (
repoPath,
localGitDir,
attributes,
+ attributesLocal,
hookPath,
assertLocal,
adjustPath,
@@ -125,8 +126,11 @@ assertLocal repo action
{- Path to a repository's gitattributes file. -}
attributes :: Repo -> FilePath
attributes repo
- | repoIsLocalBare repo = repoPath repo ++ "/info/.gitattributes"
- | otherwise = repoPath repo ++ "/.gitattributes"
+ | repoIsLocalBare repo = attributesLocal repo
+ | otherwise = repoPath repo </> ".gitattributes"
+
+attributesLocal :: Repo -> FilePath
+attributesLocal repo = localGitDir repo </> "info" </> "attributes"
{- Path to a given hook script in a repository, only if the hook exists
- and is executable. -}
diff --git a/Limit.hs b/Limit.hs
index 6930ab06d..321c1122b 100644
--- a/Limit.hs
+++ b/Limit.hs
@@ -201,22 +201,22 @@ limitAnything _ _ = return True
{- Adds a limit to skip files not believed to be present in all
- repositories in the specified group. -}
addInAllGroup :: String -> Annex ()
-addInAllGroup groupname = do
- m <- groupMap
- addLimit $ limitInAllGroup m groupname
-
-limitInAllGroup :: GroupMap -> MkLimit Annex
-limitInAllGroup m groupname
- | S.null want = Right $ const $ const $ return True
- | otherwise = Right $ \notpresent -> checkKey $ check notpresent
- where
- want = fromMaybe S.empty $ M.lookup groupname $ uuidsByGroup m
- check notpresent key
+addInAllGroup groupname = addLimit $ limitInAllGroup groupMap groupname
+
+limitInAllGroup :: Annex GroupMap -> MkLimit Annex
+limitInAllGroup getgroupmap groupname = Right $ \notpresent mi -> do
+ m <- getgroupmap
+ let want = fromMaybe S.empty $ M.lookup groupname $ uuidsByGroup m
+ if S.null want
+ then return True
-- optimisation: Check if a wanted uuid is notpresent.
- | not (S.null (S.intersection want notpresent)) = return False
- | otherwise = do
- present <- S.fromList <$> Remote.keyLocations key
- return $ S.null $ want `S.difference` present
+ else if not (S.null (S.intersection want notpresent))
+ then return False
+ else checkKey (check want) mi
+ where
+ check want key = do
+ present <- S.fromList <$> Remote.keyLocations key
+ return $ S.null $ want `S.difference` present
{- Adds a limit to skip files not using a specified key-value backend. -}
addInBackend :: String -> Annex ()
diff --git a/Logs/PreferredContent.hs b/Logs/PreferredContent.hs
index c21d67010..035c098f6 100644
--- a/Logs/PreferredContent.hs
+++ b/Logs/PreferredContent.hs
@@ -102,7 +102,7 @@ makeMatcher groupmap configmap groupwantedmap u = go True True
| null (lefts tokens) = generate $ rights tokens
| otherwise = unknownMatcher u
where
- tokens = exprParser matchstandard matchgroupwanted groupmap configmap (Just u) expr
+ tokens = exprParser matchstandard matchgroupwanted (pure groupmap) configmap (Just u) expr
matchstandard
| expandstandard = maybe (unknownMatcher u) (go False False)
(standardPreferredContent <$> getStandardGroup mygroups)
@@ -133,7 +133,7 @@ checkPreferredContentExpression expr = case parsedToMatcher tokens of
Left e -> Just e
Right _ -> Nothing
where
- tokens = exprParser matchAll matchAll emptyGroupMap M.empty Nothing expr
+ tokens = exprParser matchAll matchAll (pure emptyGroupMap) M.empty Nothing expr
{- Puts a UUID in a standard group, and sets its preferred content to use
- the standard expression for that group (unless preferred content is
diff --git a/Upgrade.hs b/Upgrade.hs
index 8d205a874..1f4a8d8de 100644
--- a/Upgrade.hs
+++ b/Upgrade.hs
@@ -18,13 +18,14 @@ import qualified Upgrade.V1
import qualified Upgrade.V2
import qualified Upgrade.V3
import qualified Upgrade.V4
+import qualified Upgrade.V5
checkUpgrade :: Version -> Annex ()
checkUpgrade = maybe noop error <=< needsUpgrade
needsUpgrade :: Version -> Annex (Maybe String)
needsUpgrade v
- | v == supportedVersion = ok
+ | v `elem` supportedVersions = ok
| v `elem` autoUpgradeableVersions = ifM (upgrade True)
( ok
, err "Automatic upgrade failed!"
@@ -40,7 +41,7 @@ upgrade :: Bool -> Annex Bool
upgrade automatic = do
upgraded <- go =<< getVersion
when upgraded $
- setVersion supportedVersion
+ setVersion currentVersion
return upgraded
where
#ifndef mingw32_HOST_OS
@@ -53,4 +54,5 @@ upgrade automatic = do
go (Just "2") = Upgrade.V2.upgrade
go (Just "3") = Upgrade.V3.upgrade automatic
go (Just "4") = Upgrade.V4.upgrade automatic
+ go (Just "5") = Upgrade.V5.upgrade automatic
go _ = return True
diff --git a/Upgrade/V1.hs b/Upgrade/V1.hs
index 801cdafa0..bcf7e0b6d 100644
--- a/Upgrade/V1.hs
+++ b/Upgrade/V1.hs
@@ -54,14 +54,14 @@ upgrade = do
ifM (fromRepo Git.repoIsLocalBare)
( do
moveContent
- setVersion supportedVersion
+ setVersion currentVersion
, do
moveContent
updateSymlinks
moveLocationLogs
Annex.Queue.flush
- setVersion supportedVersion
+ setVersion currentVersion
)
Upgrade.V2.upgrade
diff --git a/Upgrade/V5.hs b/Upgrade/V5.hs
new file mode 100644
index 000000000..cf273bb16
--- /dev/null
+++ b/Upgrade/V5.hs
@@ -0,0 +1,18 @@
+{- git-annex v5 -> v6 uppgrade support
+ -
+ - Copyright 2015 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Upgrade.V5 where
+
+import Common.Annex
+import Config
+
+upgrade :: Bool -> Annex Bool
+upgrade automatic = do
+ unless automatic $
+ showAction "v5 to v6"
+ configureSmudgeFilter
+ return True
diff --git a/debian/changelog b/debian/changelog
index 80a44c175..87affe138 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+ * annex.version increased to 6, but version 5 is also still supported.
+ * The upgrade to version 6 is not done fully automatically, because
+ upgrading a direct mode repository to version 6 will prevent old
+ versions of git-annex from working in that repository.
+ * smudge: New command, used for git smudge filter.
+ This will replace direct mode.
+ * init: Configure .git/info/attributes to use git-annex as a smudge
+ filter. Note that this changes the default behavior of git add in a
+ newly initialized repository; it will add files to the annex.
+
git-annex (5.20151117) UNRELEASED; urgency=medium
* Build with -j1 again to get reproducible build.
diff --git a/doc/direct_mode.mdwn b/doc/direct_mode.mdwn
index 4c2cb2dd7..d3e1067f9 100644
--- a/doc/direct_mode.mdwn
+++ b/doc/direct_mode.mdwn
@@ -9,6 +9,13 @@ understand how to update its working tree.
[[!toc]]
+## deprecated
+
+Direct mode is deprecated! Intead, git-annex v6 repositories can simply
+have files that are unlocked and thus can be directly accessed and
+modified. See [[upgrades]] for details about the transition to v6
+repositories.
+
## enabling (and disabling) direct mode
Normally, git-annex repositories start off in indirect mode. With some
diff --git a/doc/git-annex-direct.mdwn b/doc/git-annex-direct.mdwn
index 457ae3116..3cade1a8c 100644
--- a/doc/git-annex-direct.mdwn
+++ b/doc/git-annex-direct.mdwn
@@ -17,12 +17,18 @@ Note that git commands that operate on the work tree will refuse to
run in direct mode repositories. Use `git annex proxy` to safely run such
commands.
+Note that the direct mode/indirect mode distinction is removed in v6
+git-annex repositories. In such a repository, you can
+use [[git-annex-unlock]](1) to make a file's content be directly present.
+
# SEE ALSO
[[git-annex]](1)
[[git-annex-indirect]](1)
+[[git-annex-unlock]](1)
+
# AUTHOR
Joey Hess <id@joeyh.name>
diff --git a/doc/git-annex-indirect.mdwn b/doc/git-annex-indirect.mdwn
index 99def6144..321e0fb36 100644
--- a/doc/git-annex-indirect.mdwn
+++ b/doc/git-annex-indirect.mdwn
@@ -11,9 +11,8 @@ git annex indirect
Switches a repository back from direct mode to the default, indirect
mode.
-Some systems cannot support git-annex in indirect mode, because they
-do not support symbolic links. Repositories on such systems instead
-default to using direct mode.
+Note that the direct mode/indirect mode distinction is removed in v6
+git-annex repositories.
# SEE ALSO
diff --git a/doc/git-annex-smudge.mdwn b/doc/git-annex-smudge.mdwn
new file mode 100644
index 000000000..c8e545367
--- /dev/null
+++ b/doc/git-annex-smudge.mdwn
@@ -0,0 +1,47 @@
+# NAME
+
+git-annex smudge - git filter driver for git-annex
+
+# SYNOPSIS
+
+git annex smudge [--clean] file
+
+# DESCRIPTION
+
+This command lets git-annex be used as a git filter driver which lets
+annexed files in the git repository to be unlocked at all times, instead
+of being symlinks.
+
+When adding a file with `git add`, the annex.largefiles config is
+consulted to decide if a given file should be added to git as-is,
+or if its content are large enough to need to use git-annex. To force a
+file that would normally be added to the annex to be added to git as-is,
+this can be temporarily overridden. For example:
+
+ git -c annex.largefiles='exclude=*' add myfile
+
+The git configuration to use this command as a filter driver is as follows.
+This is normally set up for you by git-annex init, so you should
+not need to configure it manually.
+
+ [filter "annex"]
+ smudge = git-annex smudge %f
+ 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
+is normally configured when a repository is initialized, with the following
+contents:
+
+ * filter=annex
+ .* !filter
+
+# SEE ALSO
+
+[[git-annex]](1)
+
+# AUTHOR
+
+Joey Hess <id@joeyh.name>
+
+Warning: Automatically converted into a man page by mdwn2man. Edit with care.
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 2020ccf3f..1a2fd6e67 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -626,6 +626,14 @@ subdirectories).
See [[git-annex-diffdriver]](1) for details.
+* `smudge`
+
+ This command lets git-annex be used as a git filter driver, allowing
+ annexed files in the git repository to be unlocked at all times, instead
+ of being symlinks.
+
+ See [[git-annex-smudge]](1) for details.
+
* `remotedaemon`
Detects when network remotes have received git pushes and fetches from them.
diff --git a/doc/todo/smudge.mdwn b/doc/todo/smudge.mdwn
index aea0c9b98..d08d600ae 100644
--- a/doc/todo/smudge.mdwn
+++ b/doc/todo/smudge.mdwn
@@ -177,8 +177,8 @@ Configuration:
the annex. Other files are passed through the smudge/clean as-is and
have their contents stored in git.
-* annex.direct is repurposed to configure how the assistant adds files.
- When set to true, they're added unlocked.
+* annex.direct is repurposed to configure how git-annex adds files.
+ When set to false, it adds symlinks and when true it adds pointer files.
git-annex clean:
@@ -306,17 +306,19 @@ just look at the repo content in the first place..
annex.version changes to 6
-Upgrade should be handled automatically.
+git config for filter.annex.smudge and filter.annex.clean is set up.
-On upgrade, update .gitattributes with a stock configuration, unless
-it already mentions "filter=annex".
+.gitattributes is updated with a stock configuration,
+unless it already mentions "filter=annex".
Upgrading a direct mode repo needs to switch it out of bare mode, and
needs to run `git annex unlock` on all files (or reach the same result).
So will need to stage changes to all annexed files.
When a repo has some clones indirect and some direct, the upgraded repo
-will have all files unlocked, necessarily in all clones.
+will have all files unlocked, necessarily in all clones. This happens
+automatically, because when the direct repos are upgraded that causes the
+files to be unlocked, while the indirect upgrades don't touch the files.
----
diff --git a/doc/upgrades.mdwn b/doc/upgrades.mdwn
index f5e9cbc3a..d69941cb1 100644
--- a/doc/upgrades.mdwn
+++ b/doc/upgrades.mdwn
@@ -43,6 +43,45 @@ conflicts first before upgrading git-annex.
The upgrade events, so far:
+## v5 -> v6 (git-annex version 6.x)
+
+The upgrade from v5 to v6 is handled manually. Run `git-annex upgrade`
+perform the upgrade.
+
+This upgrade does away with the direct mode/indirect mode distinction.
+A v6 git-annex repository can have some files locked and other files
+unlocked, and all git and git-annex commands can be used on both locked and
+unlocked files. (Although for locked files to work, the filesystem
+must support symbolic links..)
+
+The behavior of some commands changes in an upgraded repository:
+
+* `git add` will add files to the annex, in unlocked mode, rather than
+ adding them directly to the git repository. To bypass that and add a file
+ directly to git, use:
+
+ git -c annex.largefiles='exclude=*' add myfile
+
+* `git annex unlock` and `git annex lock` change how the pointer to
+ the annexed content is stored in git.
+
+All places that a direct mode repository is cloned to should be
+running git-annex version 6.x before you upgrade the repository.
+This is necessary because the contents of the repository are changed
+in the upgrade, and the old version of git-annex won't be able to
+access files after the repo is upgraded.
+
+If a repository is only used in indirect mode, you can use git-annex
+v5 and v6 in different clones of the same indirect mode repository without
+problems.
+
+On upgrade, all files in a direct mode repository will be converted to
+unlocked files. The upgrade will need to stage changes to all files in
+the git repository.
+
+If a repository has some clones using direct mode and some using indirect
+mode, all the files will end up unlocked in all clones after the upgrade.
+
## v4 -> v5 (git-annex version 5.x)
The upgrade from v4 to v5 is handled