0c13d3065e
Pass subcommand as a regular param, which allows passing git parameters like -c before it. This was already done in the pipeing set of functions, but not the command running set.
102 lines
3 KiB
Haskell
102 lines
3 KiB
Haskell
{- git branch stuff
|
|
-
|
|
- Copyright 2011 Joey Hess <joey@kitenet.net>
|
|
-
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
-}
|
|
|
|
{-# LANGUAGE BangPatterns #-}
|
|
|
|
module Git.Branch where
|
|
|
|
import Common
|
|
import Git
|
|
import Git.Sha
|
|
import Git.Command
|
|
|
|
{- The currently checked out branch.
|
|
-
|
|
- In a just initialized git repo before the first commit,
|
|
- symbolic-ref will show the master branch, even though that
|
|
- branch is not created yet. So, this also looks at show-ref HEAD
|
|
- to double-check.
|
|
-}
|
|
current :: Repo -> IO (Maybe Git.Ref)
|
|
current r = do
|
|
v <- currentUnsafe r
|
|
case v of
|
|
Nothing -> return Nothing
|
|
Just branch ->
|
|
ifM (null <$> pipeReadStrict [Param "show-ref", Param $ show branch] r)
|
|
( return Nothing
|
|
, return v
|
|
)
|
|
|
|
{- The current branch, which may not really exist yet. -}
|
|
currentUnsafe :: Repo -> IO (Maybe Git.Ref)
|
|
currentUnsafe r = parse . firstLine
|
|
<$> pipeReadStrict [Param "symbolic-ref", Param "HEAD"] r
|
|
where
|
|
parse l
|
|
| null l = Nothing
|
|
| otherwise = Just $ Git.Ref l
|
|
|
|
{- 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 . null <$> diffs
|
|
where
|
|
diffs = pipeReadStrict
|
|
[ 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 =
|
|
-- First, check that the branch does not contain any
|
|
-- new commits that are not in the first ref. If it does,
|
|
-- cannot fast-forward.
|
|
ifM (changed first branch repo)
|
|
( no_ff
|
|
, maybe no_ff do_ff =<< findbest first rest
|
|
)
|
|
where
|
|
no_ff = return False
|
|
do_ff to = do
|
|
run [Param "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
|
|
|
|
{- Commits the index into the specified branch (or other ref),
|
|
- with the specified parent refs, and returns the committed sha -}
|
|
commit :: String -> Branch -> [Ref] -> Repo -> IO Sha
|
|
commit message branch parentrefs repo = do
|
|
tree <- getSha "write-tree" $
|
|
pipeReadStrict [Param "write-tree"] repo
|
|
sha <- getSha "commit-tree" $ pipeWriteRead
|
|
(map Param $ ["commit-tree", show tree] ++ ps)
|
|
message repo
|
|
run [Param "update-ref", Param $ show branch, Param $ show sha] repo
|
|
return sha
|
|
where
|
|
ps = concatMap (\r -> ["-p", show r]) parentrefs
|