diff --git a/Git/Blob.hs b/Git/Blob.hs
--- a/Git/Blob.hs
+++ b/Git/Blob.hs
@@ -29,9 +29,9 @@
 blobContentsToByteString (BlobStringLazy bs) =
     return $ B.concat (BL.toChunks bs)
 blobContentsToByteString (BlobStream bs) =
-    B.concat . BL.toChunks <$> (bs $$ sinkLazy)
+    B.concat . BL.toChunks <$> (runConduit $ bs .| sinkLazy)
 blobContentsToByteString (BlobSizedStream bs _) =
-    B.concat . BL.toChunks <$> (bs $$ sinkLazy)
+    runConduit $ B.concat . BL.toChunks <$> (bs .| sinkLazy)
 
 blobToByteString :: MonadGit r m => Blob r m -> m ByteString
 blobToByteString (Blob _ contents) = blobContentsToByteString contents
@@ -40,8 +40,8 @@
                              => BlobContents m -> m BL.ByteString
 blobContentsToLazyByteString (BlobString bs) = return $ BL.fromChunks [bs]
 blobContentsToLazyByteString (BlobStringLazy bs) = return bs
-blobContentsToLazyByteString (BlobStream bs) = bs $$ sinkLazy
-blobContentsToLazyByteString (BlobSizedStream bs _) = bs $$ sinkLazy
+blobContentsToLazyByteString (BlobStream bs) = runConduit $ bs .| sinkLazy
+blobContentsToLazyByteString (BlobSizedStream bs _) = runConduit $ bs .| sinkLazy
 
 blobToLazyByteString :: MonadGit r m => Blob r m -> m BL.ByteString
 blobToLazyByteString (Blob _ contents) = blobContentsToLazyByteString contents
@@ -49,19 +49,19 @@
 writeBlob :: (MonadGit r m, MonadIO m, MonadResource m)
           => FilePath -> BlobContents m -> m ()
 writeBlob path (BlobString bs)         = liftIO $ B.writeFile path bs
-writeBlob path (BlobStringLazy bs)     = sourceLazy bs $$ sinkFile path
-writeBlob path (BlobStream str)        = str $$ sinkFile path
-writeBlob path (BlobSizedStream str _) = str $$ sinkFile path
+writeBlob path (BlobStringLazy bs)     = runConduit $ sourceLazy bs .| sinkFile path
+writeBlob path (BlobStream str)        = runConduit $ str .| sinkFile path
+writeBlob path (BlobSizedStream str _) = runConduit $ str .| sinkFile path
 
 treeBlobEntries :: MonadGit r m
                 => Tree r -> m [(TreeFilePath, BlobOid r, BlobKind)]
-treeBlobEntries tree = sourceTreeBlobEntries tree $$ sinkList
+treeBlobEntries tree = runConduit $ sourceTreeBlobEntries tree .| sinkList
 
 sourceTreeBlobEntries
     :: MonadGit r m
-    => Tree r -> Producer m (TreeFilePath, BlobOid r, BlobKind)
+    => Tree r -> ConduitT i (TreeFilePath, BlobOid r, BlobKind) m ()
 sourceTreeBlobEntries tree =
-    sourceTreeEntries tree =$= awaitForever go
+    sourceTreeEntries tree .| awaitForever go
   where
     go (fp ,BlobEntry oid k) = yield (fp, oid, k)
     go _ = return ()
diff --git a/Git/Commit.hs b/Git/Commit.hs
--- a/Git/Commit.hs
+++ b/Git/Commit.hs
@@ -67,9 +67,9 @@
             -> CommitOid r         -- ^ The commit we need
             -> m [CommitOid r]     -- ^ All the objects in between
 listCommits mhave need =
-    sourceObjects mhave need False
-        $= mapMC (\(CommitObjOid c) -> return c)
-        $$ sinkList
+    runConduit $ sourceObjects mhave need False
+        .| mapMC (\(CommitObjOid c) -> return c)
+        .| sinkList
 
 traverseCommits :: MonadGit r m => (CommitOid r -> m a) -> CommitOid r -> m [a]
 traverseCommits f need = mapM f =<< listCommits Nothing need
diff --git a/Git/Commit/Push.hs b/Git/Commit/Push.hs
--- a/Git/Commit/Push.hs
+++ b/Git/Commit/Push.hs
@@ -4,8 +4,8 @@
 import           Control.Monad
 import           Control.Monad.Catch
 import           Control.Monad.IO.Class
+import           Control.Monad.IO.Unlift
 import           Control.Monad.Trans.Class
-import           Control.Monad.Trans.Control
 import           Data.Function
 import qualified Data.HashSet as HashSet
 import           Data.List
@@ -46,8 +46,8 @@
     -- updateReference_ remoteRefName (RefObj cref)
     return cref
 
-copyRepository :: (MonadGit r m, MonadIO m, MonadBaseControl IO m,
-                   MonadGit s (t m), MonadTrans t, MonadBaseControl IO (t m))
+copyRepository :: (MonadGit r m, MonadUnliftIO m,
+                   MonadGit s (t m), MonadTrans t, MonadUnliftIO (t m))
                 => RepositoryFactory (t m) m s
                 -> Maybe (CommitOid r)
                 -> Text
diff --git a/Git/Object.hs b/Git/Object.hs
--- a/Git/Object.hs
+++ b/Git/Object.hs
@@ -13,7 +13,7 @@
             -> Bool                -- ^ Include commit trees also?
             -> m [ObjectOid r]     -- ^ All the objects in between
 listObjects mhave need alsoTrees =
-    sourceObjects mhave need alsoTrees $$ sinkList
+    runConduit $ sourceObjects mhave need alsoTrees .| sinkList
 
 traverseObjects :: MonadGit r m => (ObjectOid r -> m a) -> CommitOid r -> m [a]
 traverseObjects f need = mapM f =<< listObjects Nothing need False
@@ -24,13 +24,13 @@
 -- | Given a list of objects (commit and top-level trees) return by
 --   'listObjects', expand it to include all subtrees and blobs as well.
 --   Ordering is preserved.
-expandTreeObjects :: MonadGit r m => Conduit (ObjectOid r) m (ObjectOid r)
+expandTreeObjects :: MonadGit r m => ConduitT (ObjectOid r) (ObjectOid r) m ()
 expandTreeObjects = awaitForever $ \obj -> case obj of
     TreeObjOid toid -> do
         yield $ TreeObjOid toid
         tr <- lift $ lookupTree toid
         sourceTreeEntries tr
-            =$= awaitForever (\ent -> case ent of
+            .| awaitForever (\ent -> case ent of
                 (_, BlobEntry oid _) -> yield $ BlobObjOid oid
                 (_, TreeEntry oid)   -> yield $ TreeObjOid oid
                 _ -> return ())
@@ -39,4 +39,4 @@
 listAllObjects :: MonadGit r m
                => Maybe (CommitOid r) -> CommitOid r -> m [ObjectOid r]
 listAllObjects mhave need =
-    sourceObjects mhave need True $= expandTreeObjects $$ sinkList
+    runConduit $ sourceObjects mhave need True .| expandTreeObjects .| sinkList
diff --git a/Git/Reference.hs b/Git/Reference.hs
--- a/Git/Reference.hs
+++ b/Git/Reference.hs
@@ -4,7 +4,7 @@
 import Git.Types
 
 listReferences :: MonadGit r m => m [RefName]
-listReferences = sourceReferences $$ sinkList
+listReferences = runConduit $ sourceReferences .| sinkList
 
 resolveReference :: MonadGit r m => RefName -> m (Maybe (Oid r))
 resolveReference name = do
diff --git a/Git/Repository.hs b/Git/Repository.hs
--- a/Git/Repository.hs
+++ b/Git/Repository.hs
@@ -1,13 +1,13 @@
 module Git.Repository where
 
-import Control.Exception.Lifted
 import Control.Monad
 import Control.Monad.IO.Class
-import Control.Monad.Trans.Control
+import Control.Monad.IO.Unlift
 import Git.Types
 import System.Directory
+import UnliftIO.Exception
 
-withNewRepository :: (MonadGit r n, MonadBaseControl IO n, MonadIO m)
+withNewRepository :: (MonadGit r n, MonadUnliftIO n, MonadUnliftIO m)
                   => RepositoryFactory n m r
                   -> FilePath -> n a -> m a
 withNewRepository factory path action = do
@@ -29,8 +29,7 @@
 
     return a
 
-withNewRepository' :: (MonadGit r n, MonadBaseControl IO n,
-                       MonadBaseControl IO m, MonadIO m)
+withNewRepository' :: (MonadGit r n, MonadUnliftIO n, MonadUnliftIO m)
                    => RepositoryFactory n m r -> FilePath -> n a -> m a
 withNewRepository' factory path action =
     bracket_ recover recover $
@@ -45,13 +44,13 @@
         exists <- doesDirectoryExist path
         when exists $ removeDirectoryRecursive path
 
-withRepository' :: (MonadGit r n, MonadBaseControl IO n, MonadIO m)
+withRepository' :: (MonadGit r n, MonadUnliftIO n, MonadUnliftIO m)
                 => RepositoryFactory n m r -> RepositoryOptions -> n a -> m a
 withRepository' factory opts action = do
     repo <- openRepository factory opts
     runRepository factory repo $ action `finally` closeRepository
 
-withRepository :: (MonadGit r n, MonadBaseControl IO n, MonadIO m)
+withRepository :: (MonadGit r n, MonadUnliftIO n, MonadUnliftIO m)
                => RepositoryFactory n m r -> FilePath -> n a -> m a
 withRepository factory path =
     withRepository' factory defaultRepositoryOptions { repoPath = path }
diff --git a/Git/Tree.hs b/Git/Tree.hs
--- a/Git/Tree.hs
+++ b/Git/Tree.hs
@@ -12,7 +12,7 @@
 import           Git.Types
 
 listTreeEntries :: MonadGit r m => Tree r -> m [(TreeFilePath, TreeEntry r)]
-listTreeEntries tree = sourceTreeEntries tree $$ sinkList
+listTreeEntries tree = runConduit $ sourceTreeEntries tree .| sinkList
 
 copyTreeEntry :: (MonadGit r m, MonadGit s (t m), MonadTrans t)
               => TreeEntry r -> HashSet Text -> t m (TreeEntry s, HashSet Text)
diff --git a/Git/Tree/Builder.hs b/Git/Tree/Builder.hs
--- a/Git/Tree/Builder.hs
+++ b/Git/Tree/Builder.hs
@@ -1,3 +1,5 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
 module Git.Tree.Builder
        ( TreeT
        , TreeBuilder(..)
diff --git a/Git/Tree/Working.hs b/Git/Tree/Working.hs
--- a/Git/Tree/Working.hs
+++ b/Git/Tree/Working.hs
@@ -1,11 +1,13 @@
+{-# LANGUAGE CPP #-}
 module Git.Tree.Working where
 
 import           Control.Applicative
-import           Control.Concurrent.Async.Lifted
+-- import           Control.Concurrent.Async.Lifted
 import           Control.Exception
 import           Control.Monad
 import           Control.Monad.IO.Class (MonadIO(..))
-import           Control.Monad.Trans.Control
+import           Control.Monad.IO.Unlift
+-- import           Control.Monad.Trans.Control
 import qualified Data.ByteString as B (readFile)
 import qualified Data.ByteString.Char8 as B8
 import           Data.Foldable (foldl')
@@ -17,8 +19,13 @@
 import           Data.Time.Clock.POSIX (posixSecondsToUTCTime)
 import           Git hiding (Options)
 import           Prelude hiding (log)
+import           UnliftIO.Async
 import           System.FilePath.Posix
+#ifndef mingw32_HOST_OS
 import           System.Posix.Files
+#else
+import           System.PosixCompat.Files
+#endif
 
 data FileEntry m = FileEntry
     { fileModTime  :: UTCTime
@@ -29,7 +36,7 @@
 
 type FileTree m = HashMap TreeFilePath (FileEntry m)
 
-readFileTree :: (MonadBaseControl IO m, MonadIO m, MonadGit r m)
+readFileTree :: (MonadGit r m, MonadUnliftIO m)
              => RefName
              -> FilePath
              -> Bool
@@ -42,7 +49,7 @@
             tr <- lookupTree . commitTree =<< lookupCommit (Tagged h')
             readFileTree' tr wdir getHash
 
-readFileTree' :: (MonadBaseControl IO m, MonadIO m, MonadGit r m)
+readFileTree' :: (MonadGit r m, MonadUnliftIO m)
               => Tree r -> FilePath -> Bool
               -> m (FileTree r)
 readFileTree' tr wdir getHash = do
diff --git a/Git/Types.hs b/Git/Types.hs
--- a/Git/Types.hs
+++ b/Git/Types.hs
@@ -7,7 +7,7 @@
 
 import           Conduit
 import           Control.Applicative
-import qualified Control.Exception.Lifted as Exc
+import           Control.Exception
 import           Control.Monad
 import           Control.Monad.Trans.State
 import           Data.ByteString (ByteString)
@@ -57,7 +57,7 @@
     lookupReference :: RefName -> m (Maybe (RefTarget r))
     updateReference :: RefName -> RefTarget r -> m ()
     deleteReference :: RefName -> m ()
-    sourceReferences :: Producer m RefName
+    sourceReferences :: ConduitT i RefName m ()
 
     -- Object lookup
     lookupObject  :: Oid r -> m (Object r m)
@@ -65,7 +65,7 @@
     sourceObjects :: Maybe (CommitOid r)    -- ^ A commit we may already have
                   -> CommitOid r            -- ^ The commit we need
                   -> Bool                   -- ^ Include commit trees also?
-                  -> Producer m (ObjectOid r) -- ^ All the objects in between
+                  -> ConduitT i (ObjectOid r) m () -- ^ All the objects in between
 
     lookupCommit  :: CommitOid r -> m (Commit r)
     lookupTree    :: TreeOid r -> m (Tree r)
@@ -80,10 +80,10 @@
 
     treeOid   :: Tree r -> m (TreeOid r)
     treeEntry :: Tree r -> TreeFilePath -> m (Maybe (TreeEntry r))
-    sourceTreeEntries :: Tree r -> Producer m (TreeFilePath, TreeEntry r)
+    sourceTreeEntries :: Tree r -> ConduitT i (TreeFilePath, TreeEntry r) m ()
 
-    diffContentsWithTree :: Source m (Either TreeFilePath ByteString)
-                         -> Tree r -> Producer m ByteString
+    diffContentsWithTree :: ConduitT () (Either TreeFilePath ByteString) m ()
+                         -> Tree r -> ConduitT i ByteString m ()
 
     -- Creating other objects
     hashContents :: BlobContents m -> m (BlobOid r)
@@ -93,23 +93,6 @@
                  -> m (Commit r)
     createTag :: CommitOid r -> Signature -> CommitMessage -> Text -> m (Tag r)
 
-    -- -- Pack files
-    -- buildPackFile :: FilePath -> [Either (CommitOid r) (TreeOid r)]
-    --               -> m FilePath
-    -- buildPackFile _ _ =
-    --     failure (BackendError "Backend does not support building pack files")
-
-    -- buildPackIndex :: FilePath -> ByteString -> m (Text, FilePath, FilePath)
-    -- buildPackIndex _ _ =
-    --     failure (BackendError "Backend does not support building pack indexes")
-
-    -- writePackFile :: FilePath -> m ()
-    -- writePackFile _ =
-    --     failure (BackendError "Backend does not support writing  pack files")
-
-    -- -- Git remotes
-    -- remoteFetch :: Text {- URI -} -> Text {- fetch spec -} -> m ()
-
 data RepositoryOptions = RepositoryOptions
     { repoPath       :: !FilePath
     , repoWorkingDir :: !(Maybe FilePath)
@@ -175,7 +158,7 @@
     , blobContents :: !(BlobContents m)
     }
 
-type ByteSource m = Source m ByteString
+type ByteSource m = ConduitT () ByteString m ()
 
 data BlobContents m = BlobString !ByteString
                     | BlobStringLazy !BL.ByteString
@@ -248,12 +231,12 @@
     , commitEncoding  :: !Text
     }
 
-sourceCommitParents :: MonadGit r m => Commit r -> Producer m (Commit r)
+sourceCommitParents :: MonadGit r m => Commit r -> ConduitT i (Commit r) m ()
 sourceCommitParents commit =
     forM_ (commitParents commit) $ yield <=< lift . lookupCommit
 
 lookupCommitParents :: MonadGit r m => Commit r -> m [Commit r]
-lookupCommitParents commit = sourceCommitParents commit $$ sinkList
+lookupCommitParents commit = runConduit $ sourceCommitParents commit .| sinkList
 
 data Signature = Signature
     { signatureName  :: !CommitAuthor
@@ -452,4 +435,4 @@
 -- jww (2013-02-11): Create a BackendException data constructor of forall
 -- e. Exception e => BackendException e, so that each can throw a derived
 -- exception.
-instance Exc.Exception GitException
+instance Exception GitException
diff --git a/Git/Working.hs b/Git/Working.hs
--- a/Git/Working.hs
+++ b/Git/Working.hs
@@ -15,15 +15,14 @@
 import System.Posix.Files
 #endif
 
-checkoutFiles :: (MonadGit r m, MonadBaseControl IO m, MonadIO m,
-                  MonadResource m)
+checkoutFiles :: (MonadGit r m, MonadResource m)
               => FilePath
               -> Tree r
               -> (TreeFilePath -> Either String FilePath)
               -> Bool
               -> m ()
 checkoutFiles destPath tree decode cloneSubmodules =
-    sourceTreeEntries tree $$ mapM_C $ \(path, entry) ->
+    runConduit $ sourceTreeEntries tree .| (mapM_C $ \(path, entry) ->
         case (destPath </>) <$> decode path of
             Left e ->  decodeError path e
             Right fullPath -> do
@@ -34,7 +33,7 @@
                     CommitEntry oid
                         -- jww (2013-12-26): Recursively clone submodules?
                         | cloneSubmodules -> cloneSubmodule oid fullPath
-                        | otherwise -> liftIO $ createDirectory fullPath
+                        | otherwise -> liftIO $ createDirectory fullPath)
   where
     decodeError path e = throwM $ PathEncodingError $
         "Could not decode path " <> T.pack (show path) <> ":" <> T.pack e
diff --git a/gitlib.cabal b/gitlib.cabal
--- a/gitlib.cabal
+++ b/gitlib.cabal
@@ -1,13 +1,14 @@
-Name:                gitlib
-Version:       3.1.1
-Synopsis:            API library for working with Git repositories
-License-file:        LICENSE
-License:             MIT
-Author:              John Wiegley
-Maintainer:          johnw@newartisans.com
-Build-Type:          Simple
-Cabal-Version:       >=1.10
-Category:            FFI
+Name:          gitlib
+Version:       3.1.2
+Synopsis:      API library for working with Git repositories
+License-file:  LICENSE
+License:       MIT
+Author:        John Wiegley
+Maintainer:    johnw@newartisans.com
+Build-Type:    Simple
+Cabal-Version: >=1.10
+Category:      FFI
+Homepage:      https://github.com/jwiegley/gitlib
 Description:
   @gitlib@ is a high-level, lazy and conduit-aware set of abstractions for
   programming with Git types.  Several different backends are available,
@@ -28,7 +29,7 @@
 --     Type:    exitcode-stdio-1.0
 --     Main-is: Doctest.hs
 --     Hs-source-dirs: test
---     Build-depends:      
+--     Build-depends:
 --           base
 --         , directory    >= 1.0
 --         , doctest      >= 0.8
@@ -42,16 +43,13 @@
           base                 >= 3 && < 5
         , base16-bytestring    >= 0.1.1.5
         , bytestring           >= 0.9.2.1
-        , conduit              >= 1.1.0
+        , conduit              >= 1.2.8
         , conduit-combinators  >= 1
         , containers           >= 0.4.2.1
         , directory            >= 1.1.0.2
         , exceptions           >= 0.5
         , filepath             >= 1.3
         , hashable             >= 1.1.2.5
-        , lifted-async         >= 0.1.1
-        , lifted-base          >= 0.2
-        , monad-control        <  1.1
         , mtl                  >= 2.1.2
         , resourcet            >= 1.1.0
         , semigroups           >= 0.11
@@ -60,9 +58,14 @@
         , time                 >= 1.4
         , transformers         >= 0.3.0.0
         , unordered-containers >= 0.2.3.0
+        , unliftio-core        >= 0.1.1
+        , unliftio
     if !os(mingw32)
         build-depends:
           unix                 >= 2.5.1.1
+    else
+        build-depends:
+          unix-compat          >= 0.4
     exposed-modules:
         Git
         Git.Blob
@@ -79,7 +82,7 @@
         Git.Types
         Git.Utils
         Git.Working
-    default-extensions: 
+    default-extensions:
         BangPatterns
         ConstraintKinds
         DeriveDataTypeable
