-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit-gone
executable file
·125 lines (106 loc) · 3.69 KB
/
git-gone
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env runghc
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative ( liftA2 )
import Control.Monad ( forM_ )
import Data.List ( elemIndex, isInfixOf, isPrefixOf )
import Data.Maybe ( catMaybes )
import qualified Data.Text as T
import System.Process ( readCreateProcess, shell )
main :: IO ()
main = do
deleteLocalMergedBranches
deleteLocalBranchesInteractively
deleteRemoteBranchesInteractively
_ <- sh "git gc --auto"
return ()
deleteLocalMergedBranches :: IO ()
deleteLocalMergedBranches = do
branches <- localMergedBranches
forM_ branches delete
deleteLocalBranchesInteractively :: IO ()
deleteLocalBranchesInteractively = do
branches <- localForceRemovableBranches
forM_ branches deleteForce
deleteRemoteBranchesInteractively :: IO ()
deleteRemoteBranchesInteractively = do
branches <- remoteForceRemovableBranches
forM_ branches deleteForce
data GitBranch = GitBranch {
remote :: Maybe String,
branch :: String
}
fromString :: String -> GitBranch
fromString expr =
let Just (remote_, branch_) = splitAt <$> elemIndex '/' expr <*> Just expr in
GitBranch { remote = Just remote_, branch = branch_ }
localMergedBranches :: IO [GitBranch]
localMergedBranches = do
lines_ <- sh "git branch --merged"
return [GitBranch { remote = Nothing, branch = line } |
line <- lines_,
not $ "*" `isPrefixOf` line,
not $ "master" `isInfixOf` line]
localForceRemovableBranches :: IO [GitBranch]
localForceRemovableBranches = do
lines_ <- sh "git branch -vv"
selectedLines <- peco
[line |
line <- lines_,
not $ "*" `isPrefixOf` line,
not $ "master" `isInfixOf` line,
": gone] " `isInfixOf` line]
pecoDefaultOption { prompt = Just "LOCAL>" }
return [GitBranch { remote = Nothing, branch = branch_ } |
line <- selectedLines,
let branch_ = head $ words line]
remoteForceRemovableBranches :: IO [GitBranch]
remoteForceRemovableBranches = do
lines_ <- sh "git branch -r --merged"
selectedLines <- peco
[line |
line <- lines_,
not $ "/HEAD" `isInfixOf` line,
not $ "/master" `isInfixOf` line]
pecoDefaultOption { prompt = Just "REMOTE>" }
return $ map (fromString . head . words) selectedLines
delete :: GitBranch -> IO ()
delete GitBranch { remote = Nothing, branch = branch_ } = do
_ <- sh $ "git branch -d " ++ shellescape branch_
return ()
delete _ = return ()
deleteForce :: GitBranch -> IO ()
deleteForce GitBranch { remote = Nothing, branch = branch_ } = do
_ <- sh $ "git branch -D " ++ shellescape branch_
return ()
deleteForce GitBranch { remote = Just remote_, branch = branch_ } = do
_ <- sh $ unwords ["git push -d", shellescape remote_, shellescape branch_]
return ()
sh :: String -> IO [String]
sh command = do
putStrLn $ "+" ++ command
out <- readCreateProcess (shell command) ""
return $ lines out
-- TODO: https://github.com/ruby/ruby/blob/4444025d16ae1a586eee6a0ac9bdd09e33833f3c/lib/shellwords.rb#L109
shellescape :: String -> String
shellescape str = T.unpack $ T.replace ">" "\\>" $ T.pack str
data PecoOption = PecoOption {
layout :: Maybe String,
prompt :: Maybe String
}
pecoDefaultOption :: PecoOption
pecoDefaultOption = PecoOption {
layout = Nothing,
prompt = Nothing
}
pecoCommand :: PecoOption -> String
pecoCommand option =
let flags = [("--layout ", layout option),
("--prompt ", prompt option)]
parts = catMaybes [(++) <$> Just flag <*> value | (flag, value) <- flags] in
unwords $ "peco" : map shellescape parts
peco :: [String] -> PecoOption -> IO [String]
peco [] _ = return []
peco input option = do
out <- readCreateProcess (shell $ pecoCommand option) $ unlines input
return $ lines out
-- vim:set ft=haskell: