diff --git a/git-freq.cabal b/git-freq.cabal
--- a/git-freq.cabal
+++ b/git-freq.cabal
@@ -1,5 +1,5 @@
 Name:                   git-freq
-Version:                0.0.1
+Version:                0.0.2
 Author:                 Fujimura Daisuke<me@fujimuradaisuke.com>
 Maintainer:             Fujimura Daisuke<me@fujimuradaisuke.com>
 License:                BSD3
@@ -14,6 +14,7 @@
   Main-Is:              Main.hs
   Default-Language:     Haskell2010
   GHC-Options:          -Wall
+                        -fno-warn-name-shadowing
   Hs-Source-Dirs:       src
   Build-Depends:        base >= 4 && < 5
                       , bytestring
@@ -21,11 +22,15 @@
                       , optparse-applicative
                       , process
                       , text
+  Other-modules:        Git.Freq
+                      , Git.Freq.Source
+                      , Git.Freq.Version
 
 test-suite spec
   Main-Is:              Spec.hs
   Default-Language:     Haskell2010
   GHC-Options:          -Wall
+                        -fno-warn-name-shadowing
   Hs-Source-Dirs:       src
                       , test
   Type:                 exitcode-stdio-1.0
diff --git a/src/Git/Freq.hs b/src/Git/Freq.hs
new file mode 100644
--- /dev/null
+++ b/src/Git/Freq.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Git.Freq where
+
+import           Control.Arrow   ((***))
+import           Data.List       (sortBy)
+import           Data.Map.Strict (Map)
+import qualified Data.Map.Strict as Map
+import           Data.Monoid
+import           Data.Text       (Text)
+import qualified Data.Text       as T
+import qualified Data.Text.IO    as T
+import           System.Process  (runInteractiveProcess)
+import           Text.Read       (readMaybe)
+
+import           Git.Freq.Source (Source)
+import qualified Git.Freq.Source as Source
+
+type FileName = Text
+type NumStat = (Int, Int)
+type Change = (FileName, NumStat)
+type Result = Map FileName NumStat
+
+parseLine :: Text -> Maybe Change
+parseLine = go . T.splitOn (T.pack "\t")
+    where go :: [Text] -> Maybe Change
+          go (_:_:"":_) = Nothing
+          go (added:deleted:filename:_) =
+            case (readIntMaybe added, readIntMaybe deleted) of
+                (Just a, Just d) -> Just (filename, (a, d))
+                _                -> Nothing
+          go _ = Nothing
+          readIntMaybe x = readMaybe (T.unpack x) :: Maybe Int
+
+walk :: Source a => a -> [Change] -> IO [Change]
+walk h changes = do
+    eof <- Source.isEOF h
+    if eof then return changes
+           else do
+             l <- Source.getLine h
+             case parseLine l of
+               Just c  -> walk h (c:changes)
+               Nothing -> walk h changes
+
+sumChanges :: [Change] -> Result
+sumChanges = foldl incrementChange Map.empty
+
+incrementChange :: Result -> Change -> Result
+incrementChange result (fileName,numstat@(a,d)) = Map.alter f fileName result
+  where
+    f numstat' = Just $ maybe numstat ((a+) *** (d+)) numstat'
+
+render :: Change -> IO ()
+render (fileName,(added,deleted)) =
+    T.putStrLn . T.pack . mconcat $ [T.unpack fileName, ",",  show added, ",", show deleted]
+
+sortResult :: [Change] -> [Change]
+sortResult = let f (_,(xa,xd)) (_,(ya,yd)) = (ya+yd) `compare` (xa+xd) in sortBy f
+
+freq :: [FilePath] -> IO ()
+freq paths = do
+    let args = ["log"
+               , "--numstat"
+               , "--pretty=\"%0\""
+               ] ++ paths
+
+    (_,out,_,_) <- runInteractiveProcess "git" args Nothing Nothing
+    freq' out >>= mapM_ render
+
+freq' :: Source a => a -> IO [Change]
+freq' source = do
+    changes <- walk source []
+    return $ sortResult . Map.toList $ sumChanges changes
diff --git a/src/Git/Freq/Source.hs b/src/Git/Freq/Source.hs
new file mode 100644
--- /dev/null
+++ b/src/Git/Freq/Source.hs
@@ -0,0 +1,19 @@
+module Git.Freq.Source
+  ( Source
+  , getLine
+  , isEOF
+  ) where
+
+import           Data.Text    (Text)
+import qualified Data.Text.IO as T
+import           Prelude      hiding (getLine)
+import           System.IO    (Handle)
+import qualified System.IO    as IO
+
+class Source s where
+    isEOF :: s -> IO Bool
+    getLine :: s -> IO Text
+
+instance Source Handle where
+    isEOF = IO.hIsEOF
+    getLine = T.hGetLine
diff --git a/src/Git/Freq/Version.hs b/src/Git/Freq/Version.hs
new file mode 100644
--- /dev/null
+++ b/src/Git/Freq/Version.hs
@@ -0,0 +1,6 @@
+module Git.Freq.Version
+  ( version
+  ) where
+
+version :: String
+version = "0.0.2"
