{- git branch stuff - - Copyright 2011 Joey Hess - - Licensed under the GNU GPL version 3 or higher. -} module Git.Branch where import qualified Data.ByteString.Lazy.Char8 as L import Common import Git {- Checks if the second branch has any commits not present on the first - branch. -} changed :: Branch -> Branch -> Repo -> IO Bool changed origbranch newbranch repo | origbranch == newbranch = return False | otherwise = not . L.null <$> diffs where diffs = Git.pipeRead [ Param "log" , Param (show origbranch ++ ".." ++ show newbranch) , Params "--oneline -n1" ] repo {- Given a set of refs that are all known to have commits not - on the branch, tries to update the branch by a fast-forward. - - In order for that to be possible, one of the refs must contain - every commit present in all the other refs. -} fastForward :: Branch -> [Ref] -> Repo -> IO Bool fastForward _ [] _ = return True fastForward branch (first:rest) repo = do -- First, check that the branch does not contain any -- new commits that are not in the first ref. If it does, -- cannot fast-forward. diverged <- changed first branch repo if diverged then no_ff else maybe no_ff do_ff =<< findbest first rest where no_ff = return False do_ff to = do Git.run "update-ref" [Param $ show branch, Param $ show to] repo return True findbest c [] = return $ Just c findbest c (r:rs) | c == r = findbest c rs | otherwise = do better <- changed c r repo worse <- changed r c repo case (better, worse) of (True, True) -> return Nothing -- divergent fail (True, False) -> findbest r rs -- better (False, True) -> findbest c rs -- worse (False, False) -> findbest c rs -- same