1{- git-annex command 2 - 3 - Copyright 2013 Joey Hess <id@joeyh.name> 4 - 5 - Licensed under the GNU AGPL version 3 or higher. 6 -} 7 8module Command.Repair where 9 10import Command 11import qualified Annex 12import qualified Git.Repair 13import qualified Annex.Branch 14import qualified Git.Ref 15import Git.Types 16import Annex.Version 17import qualified Utility.RawFilePath as R 18 19cmd :: Command 20cmd = noCommit $ dontCheck repoExists $ 21 command "repair" SectionMaintenance 22 "recover broken git repository" 23 paramNothing (withParams seek) 24 25seek :: CmdParams -> CommandSeek 26seek = withNothing (commandAction start) 27 28start :: CommandStart 29start = starting "repair" (ActionItemOther Nothing) (SeekInput []) $ 30 next $ runRepair =<< Annex.getState Annex.force 31 32runRepair :: Bool -> Annex Bool 33runRepair forced = do 34 (ok, modifiedbranches) <- inRepo $ 35 Git.Repair.runRepair isAnnexSyncBranch forced 36 -- This command can be run in git repos not using git-annex, 37 -- so avoid git annex branch stuff in that case. 38 whenM (isJust <$> getVersion) $ 39 repairAnnexBranch modifiedbranches 40 return ok 41 42{- After git repository repair, the .git/annex/index file could 43 - still be broken, by pointing to bad objects, or might just be corrupt on 44 - its own. Since this index file is not used to stage things 45 - for long durations of time, it can safely be deleted if it is broken. 46 - 47 - Otherwise, if the git-annex branch was modified by the repair, 48 - commit the index file to the git-annex branch. 49 - This way, if the git-annex branch got rewound to an old version by 50 - the repository repair, or was completely deleted, this will get it back 51 - to a good state. Note that in the unlikely case where the git-annex 52 - branch was rewound to a state that, had new changes from elsewhere not 53 - yet reflected in the index, this does properly merge those into the 54 - index before committing. 55 -} 56repairAnnexBranch :: [Branch] -> Annex () 57repairAnnexBranch modifiedbranches 58 | Annex.Branch.fullname `elem` modifiedbranches = ifM okindex 59 ( commitindex 60 , do 61 nukeindex 62 missingbranch 63 ) 64 | otherwise = ifM okindex 65 ( noop 66 , do 67 nukeindex 68 ifM (null <$> inRepo (Git.Ref.matching [Annex.Branch.fullname])) 69 ( missingbranch 70 , liftIO $ putStrLn "No data was lost." 71 ) 72 ) 73 where 74 okindex = Annex.Branch.withIndex $ inRepo Git.Repair.checkIndex 75 commitindex = do 76 Annex.Branch.forceCommit "committing index after git repository repair" 77 liftIO $ putStrLn "Successfully recovered the git-annex branch using .git/annex/index" 78 nukeindex = do 79 inRepo $ removeWhenExistsWith R.removeLink . gitAnnexIndex 80 liftIO $ putStrLn "Had to delete the .git/annex/index file as it was corrupt." 81 missingbranch = liftIO $ putStrLn "Since the git-annex branch is not up-to-date anymore. It would be a very good idea to run: git annex fsck --fast" 82 83trackingOrSyncBranch :: Ref -> Bool 84trackingOrSyncBranch b = Git.Repair.isTrackingBranch b || isAnnexSyncBranch b 85 86isAnnexSyncBranch :: Ref -> Bool 87isAnnexSyncBranch b = "refs/synced/" `isPrefixOf` fromRef b 88