From 7ce9a3793d91c210343a1e5ea60053dccab5a12c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 9 Jun 2014 18:01:30 -0400 Subject: avoid bad commits after interrupted direct mode sync (or merge) It was possible for a interrupted sync or merge in direct mode to leave the work tree out of sync with the last recorded commit. This would result in the next commit seeing files missing from the work tree, and committing their removal. Now, a direct mode merge happens not only in a throwaway work tree, but using a temporary index file, and without any commits or index changes being made until the real work tree has been updated. If the merge is interrupted, the work tree may have some updated files, but worst case a commit will redundantly commit changes that come from the merge. This commit was sponsored by Tony Cantor. --- Git/Branch.hs | 19 +++++++++++++++++-- Git/DiffTree.hs | 2 +- Git/Index.hs | 4 ++++ Git/Merge.hs | 14 +++++++++++++- 4 files changed, 35 insertions(+), 4 deletions(-) (limited to 'Git') diff --git a/Git/Branch.hs b/Git/Branch.hs index d182ceb39..7c7e44d75 100644 --- a/Git/Branch.hs +++ b/Git/Branch.hs @@ -52,7 +52,22 @@ changed origbranch newbranch repo diffs = pipeReadStrict [ Param "log" , Param (fromRef origbranch ++ ".." ++ fromRef newbranch) - , Params "--oneline -n1" + , Param "-n1" + , Param "--pretty=%H" + ] repo + +{- Check if it's possible to fast-forward from the old + - ref to the new ref. + - + - This requires there to be a path from the old to the new. -} +fastForwardable :: Ref -> Ref -> Repo -> IO Bool +fastForwardable old new repo = not . null <$> + pipeReadStrict + [ Param "log" + , Param $ fromRef old ++ ".." ++ fromRef new + , Param "-n1" + , Param "--pretty=%H" + , Param "--ancestry-path" ] repo {- Given a set of refs that are all known to have commits not @@ -74,7 +89,7 @@ fastForward branch (first:rest) repo = where no_ff = return False do_ff to = do - run [Param "update-ref", Param $ fromRef branch, Param $ fromRef to] repo + update branch to repo return True findbest c [] = return $ Just c findbest c (r:rs) diff --git a/Git/DiffTree.hs b/Git/DiffTree.hs index 9e4fef9d6..59de60871 100644 --- a/Git/DiffTree.hs +++ b/Git/DiffTree.hs @@ -49,7 +49,7 @@ diffIndex :: Ref -> Repo -> IO ([DiffTreeItem], IO Bool) diffIndex ref = diffIndex' ref [Param "--cached"] {- Diffs between a tree and the working tree. Does nothing if there is not - - yet a commit in the repository, of if the repository is bare. -} + - yet a commit in the repository, or if the repository is bare. -} diffWorkTree :: Ref -> Repo -> IO ([DiffTreeItem], IO Bool) diffWorkTree ref repo = ifM (Git.Ref.headExists repo) diff --git a/Git/Index.hs b/Git/Index.hs index d9d5b03bf..d712245a8 100644 --- a/Git/Index.hs +++ b/Git/Index.hs @@ -30,3 +30,7 @@ override index = do indexFile :: Repo -> FilePath indexFile r = localGitDir r "index" + +{- Git locks the index by creating this file. -} +indexFileLock :: Repo -> FilePath +indexFileLock r = indexFile r ++ ".lock" diff --git a/Git/Merge.hs b/Git/Merge.hs index 948e09e01..d661db978 100644 --- a/Git/Merge.hs +++ b/Git/Merge.hs @@ -1,6 +1,6 @@ {- git merging - - - Copyright 2012 Joey Hess + - Copyright 2012, 2014 Joey Hess - - Licensed under the GNU GPL version 3 or higher. -} @@ -19,3 +19,15 @@ mergeNonInteractive branch | otherwise = merge [Param "--no-edit", Param $ fromRef branch] where merge ps = runBool $ Param "merge" : ps + +{- Stage the merge into the index, but do not commit it.-} +stageMerge :: Ref -> Repo -> IO Bool +stageMerge branch = runBool + [ Param "merge" + , Param "--quiet" + , Param "--no-commit" + -- Without this, a fast-forward merge is done, since it involves no + -- commit. + , Param "--no-ff" + , Param $ fromRef branch + ] -- cgit v1.2.3