diff options
author | Joey Hess <joey@kitenet.net> | 2013-10-21 16:19:00 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2013-10-21 16:20:54 -0400 |
commit | afe0cc0bb4fbe3876c35462dece4670617263877 (patch) | |
tree | f23797ee89c453d7c82f35e47bb5fc197662a5f4 | |
parent | 727566ad23efc6c36a4a4473b3299af913f6ce03 (diff) |
corrupt branch resetting (but not yet reflog walking)
-rw-r--r-- | Git/RecoverRepository.hs | 43 | ||||
-rw-r--r-- | doc/design/assistant/disaster_recovery.mdwn | 9 | ||||
-rw-r--r-- | git-recover-repository.hs | 21 |
3 files changed, 58 insertions, 15 deletions
diff --git a/Git/RecoverRepository.hs b/Git/RecoverRepository.hs index f40450f46..330063abe 100644 --- a/Git/RecoverRepository.hs +++ b/Git/RecoverRepository.hs @@ -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 diff --git a/doc/design/assistant/disaster_recovery.mdwn b/doc/design/assistant/disaster_recovery.mdwn index 1a2b55477..770c8f43a 100644 --- a/doc/design/assistant/disaster_recovery.mdwn +++ b/doc/design/assistant/disaster_recovery.mdwn @@ -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.) diff --git a/git-recover-repository.hs b/git-recover-repository.hs index 66b1708f8..3a002e72c 100644 --- a/git-recover-repository.hs +++ b/git-recover-repository.hs @@ -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." |