properly handle deleted files when processing ls-files --unmerged

This commit is contained in:
Joey Hess 2012-06-27 12:09:01 -04:00
parent 8e8439a519
commit 051c68041b
2 changed files with 94 additions and 18 deletions

View file

@ -155,10 +155,30 @@ mergeAnnex = do
Annex.Branch.forceUpdate Annex.Branch.forceUpdate
stop stop
mergeFrom :: Git.Ref -> CommandCleanup mergeFrom :: Git.Ref -> Annex Bool
mergeFrom branch = do mergeFrom branch = do
showOutput showOutput
inRepo $ Git.Merge.mergeNonInteractive branch ok <- inRepo $ Git.Merge.mergeNonInteractive branch
if ok
then return ok
else resolveMerge
{- Resolves a conflicted merge. It's important that any conflicts be
- resolved in a way that itself avoids later merge conflicts, since
- multiple repositories may be doing this concurrently.
-
- Only annexed files are resolved; other files are left for the user to
- handle.
-
- This uses the Keys pointed to by the files to construct new
- filenames. So a conflicted merge of file foo will delete it,
- and add files foo.KEYA and foo.KEYB.
-
- A conflict can also result due to
-}
resolveMerge :: Annex Bool
resolveMerge = do
changed :: Remote -> Git.Ref -> Annex Bool changed :: Remote -> Git.Ref -> Annex Bool
changed remote b = do changed remote b = do

View file

@ -13,6 +13,9 @@ module Git.LsFiles (
changedUnstaged, changedUnstaged,
typeChanged, typeChanged,
typeChangedStaged, typeChangedStaged,
Conflicting(..),
Unmerged(..),
unmerged,
) where ) where
import Common import Common
@ -78,25 +81,78 @@ typeChanged' ps l repo = do
prefix = [Params "diff --name-only --diff-filter=T -z"] prefix = [Params "diff --name-only --diff-filter=T -z"]
suffix = Param "--" : map File l suffix = Param "--" : map File l
{- A item in conflict has two possible values.
- Either can be Nothing, when that side deleted the file. -}
data Conflicting v = Conflicting
{ valUs :: Maybe v
, valThem :: Maybe v
} deriving (Show)
isConflicting :: Eq a => Conflicting a -> Bool
isConflicting (Conflicting a b) = a /= b
data Unmerged = Unmerged data Unmerged = Unmerged
{ unmergedFile :: FilePath { unmergedFile :: FilePath
, unmergedBlobType :: BlobType , unmergedBlobType :: Conflicting BlobType
, unmergedSha :: Sha , unmergedSha :: Conflicting Sha
} } deriving (Show)
{- Returns a list of the files in the specified locations that have {- Returns a list of the files in the specified locations that have
- unresolved merge conflicts. Each unmerged file will have duplicates - unresolved merge conflicts.
- in the list for each unmerged version (typically two). -} -
- ls-files outputs multiple lines per conflicting file, each with its own
- stage number:
- 1 = old version, can be ignored
- 2 = us
- 3 = them
- If a line is omitted, that side deleted the file.
-}
unmerged :: [FilePath] -> Repo -> IO [Unmerged] unmerged :: [FilePath] -> Repo -> IO [Unmerged]
unmerged l repo = catMaybes . map parse <$> list repo unmerged l repo = reduceUnmerged [] . catMaybes . map parseUnmerged <$> list repo
where where
list = pipeNullSplit $ Params "ls-files --unmerged -z --" : map File l files = map File l
parse s list = pipeNullSplit $ Params "ls-files --unmerged -z --" : files
| null file || length ws < 2 = Nothing
| otherwise = do data InternalUnmerged = InternalUnmerged
blobtype <- readBlobType (ws !! 0) { isus :: Bool
sha <- extractSha (ws !! 1) , ifile :: FilePath
return $ Unmerged file blobtype sha , iblobtype :: Maybe BlobType
where , isha :: Maybe Sha
(metadata, file) = separate (== '\t') s } deriving (Show)
ws = words metadata
parseUnmerged :: String -> Maybe InternalUnmerged
parseUnmerged s
| null file || length ws < 3 = Nothing
| otherwise = do
stage <- readish (ws !! 2)
unless (stage == 2 || stage == 3) $
fail undefined -- skip stage 1
blobtype <- readBlobType (ws !! 0)
sha <- extractSha (ws !! 1)
return $ InternalUnmerged (stage == 2) file (Just blobtype) (Just sha)
where
(metadata, file) = separate (== '\t') s
ws = words metadata
reduceUnmerged :: [Unmerged] -> [InternalUnmerged] -> [Unmerged]
reduceUnmerged c [] = c
reduceUnmerged c (i:is) = reduceUnmerged (new:c) rest
where
(rest, sibi) = findsib i is
(blobtypeA, blobtypeB, shaA, shaB)
| isus i = (iblobtype i, iblobtype sibi, isha i, isha sibi)
| otherwise = (iblobtype sibi, iblobtype i, isha sibi, isha i)
new = Unmerged
{ unmergedFile = ifile i
, unmergedBlobType = Conflicting blobtypeA blobtypeB
, unmergedSha = Conflicting shaA shaB
}
findsib templatei [] = ([], deleted templatei)
findsib templatei (i:is)
| ifile i == ifile templatei = (is, i)
| otherwise = (i:is, deleted templatei)
deleted templatei = templatei
{ isus = not (isus templatei)
, iblobtype = Nothing
, isha = Nothing
}