fixed reconcileStaged crash when index is locked or in conflict
Eg, when git commit runs the smudge filter.
Commit 428c91606b
introduced the crash,
as write-tree fails in those situations. Now it will work, and git-annex
always gets up-to-date information even in those situations. It does
need to do a bit more work, each time git-annex is run with the index
locked. Although if the index is unmodified from the last time
write-tree succeeded, that work is avoided.
This commit is contained in:
parent
3698e804d4
commit
efae085272
3 changed files with 47 additions and 26 deletions
|
@ -45,7 +45,7 @@ import Git.Command
|
||||||
import Git.Types
|
import Git.Types
|
||||||
import Git.Index
|
import Git.Index
|
||||||
import Git.Sha
|
import Git.Sha
|
||||||
import Git.Branch (writeTree, update')
|
import Git.Branch (writeTreeQuiet, update')
|
||||||
import qualified Git.Ref
|
import qualified Git.Ref
|
||||||
import Config.Smudge
|
import Config.Smudge
|
||||||
import qualified Utility.RawFilePath as R
|
import qualified Utility.RawFilePath as R
|
||||||
|
@ -226,35 +226,48 @@ reconcileStaged qh = do
|
||||||
withTSDelta (liftIO . genInodeCache gitindex) >>= \case
|
withTSDelta (liftIO . genInodeCache gitindex) >>= \case
|
||||||
Just cur ->
|
Just cur ->
|
||||||
liftIO (maybe Nothing readInodeCache <$> catchMaybeIO (readFile indexcache)) >>= \case
|
liftIO (maybe Nothing readInodeCache <$> catchMaybeIO (readFile indexcache)) >>= \case
|
||||||
Nothing -> go cur indexcache
|
Nothing -> go cur indexcache =<< getindextree
|
||||||
Just prev -> ifM (compareInodeCaches prev cur)
|
Just prev -> ifM (compareInodeCaches prev cur)
|
||||||
( noop
|
( noop
|
||||||
, go cur indexcache
|
, go cur indexcache =<< getindextree
|
||||||
)
|
)
|
||||||
Nothing -> noop
|
Nothing -> noop
|
||||||
where
|
where
|
||||||
lastindexref = Ref "refs/annex/last-index"
|
lastindexref = Ref "refs/annex/last-index"
|
||||||
|
|
||||||
go cur indexcache = do
|
getindextree = inRepo writeTreeQuiet
|
||||||
oldtree <- fromMaybe emptyTree
|
|
||||||
<$> inRepo (Git.Ref.sha lastindexref)
|
getoldtree = fromMaybe emptyTree <$> inRepo (Git.Ref.sha lastindexref)
|
||||||
newtree <- inRepo writeTree
|
|
||||||
|
go cur indexcache (Just newtree) = do
|
||||||
|
oldtree <- getoldtree
|
||||||
when (oldtree /= newtree) $ do
|
when (oldtree /= newtree) $ do
|
||||||
(l, cleanup) <- inRepo $ pipeNullSplit' $
|
updatetodiff (fromRef oldtree) (fromRef newtree)
|
||||||
diff oldtree newtree
|
|
||||||
changed <- procdiff l False
|
|
||||||
void $ liftIO cleanup
|
|
||||||
-- Flush database changes immediately
|
|
||||||
-- so other processes can see them.
|
|
||||||
when changed $
|
|
||||||
liftIO $ H.flushDbQueue qh
|
|
||||||
liftIO $ writeFile indexcache $ showInodeCache cur
|
liftIO $ writeFile indexcache $ showInodeCache cur
|
||||||
-- Storing the tree in a ref makes sure it does not
|
-- Storing the tree in a ref makes sure it does not
|
||||||
-- get garbage collected, and is available to diff
|
-- get garbage collected, and is available to diff
|
||||||
-- against next time.
|
-- against next time.
|
||||||
inRepo $ update' lastindexref newtree
|
inRepo $ update' lastindexref newtree
|
||||||
|
-- git write-tree will fail if the index is locked or when there is
|
||||||
|
-- a merge conflict. To get up-to-date with the current index,
|
||||||
|
-- diff --cached with the old index tree. The current index tree
|
||||||
|
-- is not known, so not recorded, and the inode cache is not updated,
|
||||||
|
-- so the next time git-annex runs, it will diff again, even
|
||||||
|
-- if the index is unchanged.
|
||||||
|
go _ _ Nothing = do
|
||||||
|
oldtree <- getoldtree
|
||||||
|
updatetodiff (fromRef oldtree) "--cached"
|
||||||
|
|
||||||
|
updatetodiff old new = do
|
||||||
|
(l, cleanup) <- inRepo $ pipeNullSplit' $ diff old new
|
||||||
|
changed <- procdiff l False
|
||||||
|
void $ liftIO cleanup
|
||||||
|
-- Flush database changes immediately
|
||||||
|
-- so other processes can see them.
|
||||||
|
when changed $
|
||||||
|
liftIO $ H.flushDbQueue qh
|
||||||
|
|
||||||
diff oldtree newtree =
|
diff old new =
|
||||||
-- Avoid running smudge or clean filters, since we want the
|
-- Avoid running smudge or clean filters, since we want the
|
||||||
-- raw output, and they would block trying to access the
|
-- raw output, and they would block trying to access the
|
||||||
-- locked database. The --raw normally avoids git diff
|
-- locked database. The --raw normally avoids git diff
|
||||||
|
@ -264,6 +277,8 @@ reconcileStaged qh = do
|
||||||
-- (The -G option may make it be used otherwise.)
|
-- (The -G option may make it be used otherwise.)
|
||||||
[ Param "-c", Param "diff.external="
|
[ Param "-c", Param "diff.external="
|
||||||
, Param "diff"
|
, Param "diff"
|
||||||
|
, Param old
|
||||||
|
, Param new
|
||||||
, Param "--raw"
|
, Param "--raw"
|
||||||
, Param "-z"
|
, Param "-z"
|
||||||
, Param "--no-abbrev"
|
, Param "--no-abbrev"
|
||||||
|
@ -279,8 +294,6 @@ reconcileStaged qh = do
|
||||||
-- Avoid other complications.
|
-- Avoid other complications.
|
||||||
, Param "--ignore-submodules=all"
|
, Param "--ignore-submodules=all"
|
||||||
, Param "--no-ext-diff"
|
, Param "--no-ext-diff"
|
||||||
, Param (fromRef oldtree)
|
|
||||||
, Param (fromRef newtree)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
procdiff (info:file:rest) changed
|
procdiff (info:file:rest) changed
|
||||||
|
|
|
@ -185,8 +185,18 @@ commitAlways :: CommitMode -> String -> Branch -> [Ref] -> Repo -> IO Sha
|
||||||
commitAlways commitmode message branch parentrefs repo = fromJust
|
commitAlways commitmode message branch parentrefs repo = fromJust
|
||||||
<$> commit commitmode True message branch parentrefs repo
|
<$> commit commitmode True message branch parentrefs repo
|
||||||
|
|
||||||
|
-- Throws exception if the index is locked, with an error message output by
|
||||||
|
-- git on stderr.
|
||||||
writeTree :: Repo -> IO Sha
|
writeTree :: Repo -> IO Sha
|
||||||
writeTree repo = getSha "write-tree" $ pipeReadStrict [Param "write-tree"] repo
|
writeTree repo = getSha "write-tree" $
|
||||||
|
pipeReadStrict [Param "write-tree"] repo
|
||||||
|
|
||||||
|
-- Avoids error output if the command fails due to eg, the index being locked.
|
||||||
|
writeTreeQuiet :: Repo -> IO (Maybe Sha)
|
||||||
|
writeTreeQuiet repo = extractSha <$> withNullHandle go
|
||||||
|
where
|
||||||
|
go nullh = pipeReadStrict' (\p -> p { std_err = UseHandle nullh })
|
||||||
|
[Param "write-tree"] repo
|
||||||
|
|
||||||
commitTree :: CommitMode -> String -> [Ref] -> Ref -> Repo -> IO Sha
|
commitTree :: CommitMode -> String -> [Ref] -> Ref -> Repo -> IO Sha
|
||||||
commitTree commitmode message parentrefs tree repo =
|
commitTree commitmode message parentrefs tree repo =
|
||||||
|
|
|
@ -70,17 +70,15 @@ pipeReadLazy params repo = assertLocal repo $ do
|
||||||
- Nonzero exit status is ignored.
|
- Nonzero exit status is ignored.
|
||||||
-}
|
-}
|
||||||
pipeReadStrict :: [CommandParam] -> Repo -> IO S.ByteString
|
pipeReadStrict :: [CommandParam] -> Repo -> IO S.ByteString
|
||||||
pipeReadStrict = pipeReadStrict' S.hGetContents
|
pipeReadStrict = pipeReadStrict' id
|
||||||
|
|
||||||
{- The reader action must be strict. -}
|
pipeReadStrict' :: (CreateProcess -> CreateProcess) -> [CommandParam] -> Repo -> IO S.ByteString
|
||||||
pipeReadStrict' :: (Handle -> IO a) -> [CommandParam] -> Repo -> IO a
|
pipeReadStrict' fp params repo = assertLocal repo $ withCreateProcess p go
|
||||||
pipeReadStrict' reader params repo = assertLocal repo $ withCreateProcess p go
|
|
||||||
where
|
where
|
||||||
p = (gitCreateProcess params repo)
|
p = fp (gitCreateProcess params repo) { std_out = CreatePipe }
|
||||||
{ std_out = CreatePipe }
|
|
||||||
|
|
||||||
go _ (Just outh) _ pid = do
|
go _ (Just outh) _ pid = do
|
||||||
output <- reader outh
|
output <- S.hGetContents outh
|
||||||
hClose outh
|
hClose outh
|
||||||
void $ waitForProcess pid
|
void $ waitForProcess pid
|
||||||
return output
|
return output
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue