This commit is contained in:
Joey Hess 2013-10-23 13:13:40 -04:00
parent 435ea52f3c
commit 1ab2ad86c7
3 changed files with 87 additions and 67 deletions

View file

@ -13,6 +13,7 @@ import qualified Annex
import qualified Git.Repair
import qualified Annex.Branch
import Git.Fsck (MissingObjects)
import Git.Types
def :: [Command]
def = [noCommit $ dontCheck repoExists $
@ -26,9 +27,10 @@ start = next $ next $ runRepair =<< Annex.getState Annex.force
runRepair :: Bool -> Annex Bool
runRepair forced = do
(ok, stillmissing) <- inRepo $ Git.Repair.runRepair forced
(ok, stillmissing, modifiedbranches) <- inRepo $
Git.Repair.runRepair forced
when ok $
repairAnnexBranch stillmissing
repairAnnexBranch stillmissing modifiedbranches
return ok
{- After git repository repair, the .git/annex/index file could
@ -36,23 +38,31 @@ runRepair forced = do
- its own. Since this index file is not used to stage things
- for long durations of time, it can safely be deleted if it is broken.
-
- Otherwise, commit the index file to the git-annex branch.
- Otherwise, if the git-annex branch was modified by the repair,
- commit the index file to the git-annex branch.
- This way, if the git-annex branch got rewound to an old version by
- the repository repair, or was completely deleted, this will get it back
- to a good state. Note that in the unlikely case where the git-annex
- branch is ok, and has new changes from elsewhere not yet reflected in
- the index, this does properly merge those into the index before
- committing.
- branch was rewound to a state that, had new changes from elsewhere not
- yet reflected in the index, this does properly merge those into the
- index before committing.
-}
repairAnnexBranch :: MissingObjects -> Annex ()
repairAnnexBranch missing = ifM okindex
( do
Annex.Branch.forceCommit "committing index after git repository repair"
liftIO $ putStrLn "Successfully recovered the git-annex branch using .git/annex/index"
, do
inRepo $ nukeFile . gitAnnexIndex
liftIO $ putStrLn "Had to delete the .git/annex/index file as it was corrupt. It would be a very good idea to run: git annex fsck --fast"
)
repairAnnexBranch :: MissingObjects -> [Branch] -> Annex ()
repairAnnexBranch missing modifiedbranches
| Annex.Branch.fullname `elem` modifiedbranches = ifM okindex
( commitindex
, do
nukeindex
liftIO $ putStrLn "Had to delete the .git/annex/index file as it was corrupt. Since the git-annex branch is not up-to-date anymore. It would be a very good idea to run: git annex fsck --fast"
)
| otherwise = ifM okindex
( noop
, nukeindex
)
where
okindex = Annex.Branch.withIndex $
inRepo $ Git.Repair.checkIndex missing
commitindex = do
Annex.Branch.forceCommit "committing index after git repository repair"
liftIO $ putStrLn "Successfully recovered the git-annex branch using .git/annex/index"
nukeindex = inRepo $ nukeFile . gitAnnexIndex

View file

@ -421,64 +421,73 @@ displayList items header
| otherwise = items
{- Put it all together. -}
runRepair :: Bool -> Repo -> IO (Bool, MissingObjects)
runRepair :: Bool -> Repo -> IO (Bool, MissingObjects, [Branch])
runRepair forced g = do
putStrLn "Running git fsck ..."
fsckresult <- findBroken False g
missing <- cleanCorruptObjects fsckresult g
stillmissing <- retrieveMissingObjects missing g
if S.null stillmissing
then successfulfinish stillmissing
if foundBroken fsckresult
then makerepairs fsckresult
else do
putStrLn $ unwords
[ show (S.size stillmissing)
, "missing objects could not be recovered!"
]
if forced
then do
(remotebranches, goodcommits) <- removeTrackingBranches stillmissing emptyGoodCommits g
unless (null remotebranches) $
putStrLn $ unwords
[ "removed"
, show (length remotebranches)
, "remote tracking branches that referred to missing objects"
]
(resetbranches, deletedbranches, _) <- resetLocalBranches stillmissing goodcommits g
displayList (map show resetbranches)
"Reset these local branches to old versions before the missing objects were committed:"
displayList (map show deletedbranches)
"Deleted these local branches, which could not be recovered due to missing objects:"
deindexedfiles <- rewriteIndex stillmissing g
displayList deindexedfiles
"Removed these missing files from the index. You should look at what files are present in your working tree and git add them back to the index when appropriate."
if null resetbranches && null deletedbranches
then successfulfinish stillmissing
else do
unless (repoIsLocalBare g) $ do
mcurr <- Branch.currentUnsafe g
case mcurr of
Nothing -> return ()
Just curr -> when (any (== curr) (resetbranches ++ deletedbranches)) $ do
putStrLn $ unwords
[ "You currently have"
, show curr
, "checked out. You may have staged changes in the index that can be committed to recover the lost state of this branch!"
]
putStrLn "Successfully recovered repository!"
putStrLn "Please carefully check that the changes mentioned above are ok.."
return (True, stillmissing)
else do
if repoIsLocalBare g
then do
putStrLn "If you have a clone of this bare repository, you should add it as a remote of this repository, and re-run git-recover-repository."
putStrLn "If there are no clones of this repository, you can instead run git-recover-repository with the --force parameter to force recovery to a possibly usable state."
else putStrLn "To force a recovery to a usable state, run this command again with the --force parameter."
return (False, stillmissing)
putStrLn "No problems found."
return (True, S.empty, [])
where
successfulfinish stillmissing = do
makerepairs fsckresult = do
missing <- cleanCorruptObjects fsckresult g
stillmissing <- retrieveMissingObjects missing g
if S.null stillmissing
then successfulfinish stillmissing []
else do
putStrLn $ unwords
[ show (S.size stillmissing)
, "missing objects could not be recovered!"
]
if forced
then continuerepairs stillmissing
else unsuccessfulfinish stillmissing
continuerepairs stillmissing = do
(remotebranches, goodcommits) <- removeTrackingBranches stillmissing emptyGoodCommits g
unless (null remotebranches) $
putStrLn $ unwords
[ "removed"
, show (length remotebranches)
, "remote tracking branches that referred to missing objects"
]
(resetbranches, deletedbranches, _) <- resetLocalBranches stillmissing goodcommits g
displayList (map show resetbranches)
"Reset these local branches to old versions before the missing objects were committed:"
displayList (map show deletedbranches)
"Deleted these local branches, which could not be recovered due to missing objects:"
deindexedfiles <- rewriteIndex stillmissing g
displayList deindexedfiles
"Removed these missing files from the index. You should look at what files are present in your working tree and git add them back to the index when appropriate."
let modifiedbranches = resetbranches ++ deletedbranches
if null resetbranches && null deletedbranches
then successfulfinish stillmissing modifiedbranches
else do
unless (repoIsLocalBare g) $ do
mcurr <- Branch.currentUnsafe g
case mcurr of
Nothing -> return ()
Just curr -> when (any (== curr) modifiedbranches) $ do
putStrLn $ unwords
[ "You currently have"
, show curr
, "checked out. You may have staged changes in the index that can be committed to recover the lost state of this branch!"
]
putStrLn "Successfully recovered repository!"
putStrLn "Please carefully check that the changes mentioned above are ok.."
return (True, stillmissing, modifiedbranches)
successfulfinish stillmissing modifiedbranches = do
mapM_ putStrLn
[ "Successfully recovered repository!"
, "You should run \"git fsck\" to make sure, but it looks like"
, "everything was recovered ok."
]
return (True, stillmissing)
return (True, stillmissing, modifiedbranches)
unsuccessfulfinish stillmissing = do
if repoIsLocalBare g
then do
putStrLn "If you have a clone of this bare repository, you should add it as a remote of this repository, and re-run git-recover-repository."
putStrLn "If there are no clones of this repository, you can instead run git-recover-repository with the --force parameter to force recovery to a possibly usable state."
else putStrLn "To force a recovery to a usable state, run this command again with the --force parameter."
return (False, stillmissing, [])

View file

@ -7,6 +7,7 @@
import System.Environment
import qualified Data.Set as S
import Data.Tuple.Utils
import Common
import qualified Git
@ -35,7 +36,7 @@ main = do
forced <- parseArgs
g <- Git.Config.read =<< Git.CurrentRepo.get
ifM (fst <$> Git.Repair.runRepair forced g)
ifM (fst3 <$> Git.Repair.runRepair forced g)
( exitSuccess
, exitFailure
)