corrupt branch resetting (but not yet reflog walking)

This commit is contained in:
Joey Hess 2013-10-21 16:19:00 -04:00
parent fcd91be6f0
commit 18487c779f
3 changed files with 58 additions and 15 deletions

View file

@ -169,11 +169,40 @@ copyObjects srcr destr = rsync
{- To deal with missing objects that cannot be recovered, resets any
- local branches to point to an old commit before the missing
- objects.
- objects. Returns all branches that were changed, and deleted.
-}
resetLocalBranches :: MissingObjects -> GoodCommits -> Repo -> IO [Branch]
resetLocalBranches missing goodcommits r = do
error "TODO"
resetLocalBranches :: MissingObjects -> GoodCommits -> Repo -> IO ([Branch], [Branch], GoodCommits)
resetLocalBranches missing goodcommits r =
go [] [] goodcommits =<< filter islocalbranch <$> getAllRefs r
where
islocalbranch b = "refs/heads/" `isPrefixOf` show b
go changed deleted gcs [] = return (changed, deleted, gcs)
go changed deleted gcs (b:bs) = do
(mc, gcs') <- findUncorruptedCommit missing gcs b r
case mc of
Just c
| c == b -> go changed deleted gcs' bs
| otherwise -> do
reset b c
go (b:changed) deleted gcs' bs
Nothing -> do
(mc', gcs'') <- findOldBranch missing gcs' b r
case mc' of
Just c
| c == b -> go changed deleted gcs' bs
| otherwise -> do
reset b c
go (b:changed) deleted gcs'' bs
Nothing -> do
nukeBranchRef b r
go changed (b:deleted) gcs'' bs
reset b c = do
nukeBranchRef b r
void $ runBool
[ Param "branch"
, Param (show $ Ref.base b)
, Param (show c)
] r
{- To deal with missing objects that cannot be recovered, removes
- any remote tracking branches that reference them. Returns a list of
@ -255,6 +284,7 @@ findUncorruptedCommit missing goodcommits branch r = do
else do
(ls, cleanup) <- pipeNullSplit
[ Param "log"
, Param "-z"
, Param "--format=%H"
, Param (show branch)
] r
@ -284,11 +314,12 @@ verifyCommit missing goodcommits commit r
| otherwise = do
(ls, cleanup) <- pipeNullSplit
[ Param "log"
, Param "-z"
, Param "--format=%H %T"
, Param (show commit)
] r
let committrees = map parse ls
if any isNothing committrees
if any isNothing committrees || null committrees
then do
void cleanup
return (False, goodcommits)
@ -304,7 +335,7 @@ verifyCommit missing goodcommits commit r
<$> extractSha commitsha
<*> extractSha treesha
_ -> Nothing
check [] = return False
check [] = return True
check ((commit, tree):rest)
| checkGoodCommit commit goodcommits = return True
| otherwise = verifyTree missing tree r <&&> check rest

View file

@ -143,8 +143,7 @@ that was found for it.
`git annex fsck --fast` to fix up any object location info.
* Remote tracking branches can just be removed, and then `git fetch`
from the remote, which will re-download missing objects from it and
reinstate the tracking branch.
* For other branches (or tags), it's best to not rewrite them, because
that could get really confusing. Instead, delete the old broken branch,
and make a "recovered/$branch" that holds the last good commit (if one
was found).
reinstate the tracking branch. **done**
* For other branches, reset them to last good commit, or delete
if none was found.
* (Decided not to touch tags.)

View file

@ -16,6 +16,7 @@ import Common
import qualified Git.CurrentRepo
import qualified Git.RecoverRepository
import qualified Git.Config
import qualified Git.Branch
header :: String
header = "Usage: git-recover-repository"
@ -34,7 +35,7 @@ parseArgs = do
enableDebugOutput :: IO ()
enableDebugOutput = do
s <- setFormatter
<$> streamHandler stderr NOTICE
<$> streamHandler stderr DEBUG -- NOTICE
<*> pure (simpleLogFormatter "$msg")
updateGlobalLogger rootLoggerName (setLevel DEBUG . setHandlers [s])
@ -66,8 +67,20 @@ main = do
, show (length remotebranches)
, "remote tracking branches that referred to missing objects"
]
localbranches <- Git.RecoverRepository.resetLocalBranches stillmissing goodcommits g
unless (null localbranches) $ do
(resetbranches, deletedbranches, _) <- Git.RecoverRepository.resetLocalBranches stillmissing goodcommits g
unless (null resetbranches) $ do
putStrLn "Reset these local branches to old versions before the missing objects were committed:"
putStr $ unlines $ map show localbranches
putStr $ unlines $ map show resetbranches
unless (null deletedbranches) $ do
putStrLn "Deleted these local branches, which could not be recovered due to missing objects:"
putStr $ unlines $ map show deletedbranches
mcurr <- Git.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!"
]
else putStrLn "To force a recovery to a usable state, run this command again with the --force parameter."