diff --git a/hpack.cabal b/hpack.cabal
--- a/hpack.cabal
+++ b/hpack.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 55dc38c5a69ab1a5dc744c1e8322a562cf343c8f4f84380100024f10784994b6
+-- hash: 3543542c356a8147c78f7d1b3e633d834653cf0d5132754f0751b712e275cc88
 
 name:           hpack
-version:        0.33.0.1
+version:        0.33.1
 synopsis:       A modern format for Haskell packages
 description:    See README at <https://github.com/sol/hpack#readme>
 category:       Development
diff --git a/src/Hpack.hs b/src/Hpack.hs
--- a/src/Hpack.hs
+++ b/src/Hpack.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE RecordWildCards #-}
 module Hpack (
 -- | /__NOTE:__/ This module is exposed to allow integration of Hpack into
@@ -32,10 +33,12 @@
 , Verbose(..)
 , Options(..)
 , Force(..)
+, GenerateHashStrategy(..)
 
 #ifdef TEST
 , hpackResultWithVersion
 , header
+, renderCabalFile
 #endif
 ) where
 
@@ -47,8 +50,9 @@
 import           System.Exit
 import           System.IO (stderr)
 import           Data.Aeson (Value)
+import           Data.Maybe
 
-import           Paths_hpack ()
+import           Paths_hpack (version)
 import           Hpack.Options
 import           Hpack.Config
 import           Hpack.Render
@@ -56,34 +60,35 @@
 import           Hpack.Utf8 as Utf8
 import           Hpack.CabalFile
 
-version :: Version
-version = makeVersion [0,33,0]
-
-programVersion :: Version -> String
-programVersion v = "hpack version " ++ Version.showVersion v
+programVersion :: Maybe Version -> String
+programVersion Nothing = "hpack"
+programVersion (Just v) = "hpack version " ++ Version.showVersion v
 
-header :: FilePath -> Version -> Hash -> String
-header p v hash = unlines [
+header :: FilePath -> Maybe Version -> (Maybe Hash) -> [String]
+header p v hash = [
     "-- This file has been generated from " ++ takeFileName p ++ " by " ++ programVersion v ++ "."
   , "--"
   , "-- see: https://github.com/sol/hpack"
-  , "--"
-  , "-- hash: " ++ hash
-  , ""
-  ]
+  ] ++ case hash of
+    Just h -> ["--" , "-- hash: " ++ h, ""]
+    Nothing -> [""]
 
 data Options = Options {
   optionsDecodeOptions :: DecodeOptions
 , optionsForce :: Force
+, optionsGenerateHashStrategy :: GenerateHashStrategy
 , optionsToStdout :: Bool
 }
 
+data GenerateHashStrategy = ForceHash | ForceNoHash | PreferHash | PreferNoHash
+  deriving (Eq, Show)
+
 getOptions :: FilePath -> [String] -> IO (Maybe (Verbose, Options))
 getOptions defaultPackageConfig args = do
   result <- parseOptions defaultPackageConfig args
   case result of
     PrintVersion -> do
-      putStrLn (programVersion version)
+      putStrLn (programVersion $ Just version)
       return Nothing
     PrintNumericVersion -> do
       putStrLn (Version.showVersion version)
@@ -91,9 +96,12 @@
     Help -> do
       printHelp
       return Nothing
-    Run options -> case options of
-      ParseOptions verbose force toStdout file -> do
-        return $ Just (verbose, Options defaultDecodeOptions {decodeOptionsTarget = file} force toStdout)
+    Run (ParseOptions verbose force hash toStdout file) -> do
+      let generateHash = case hash of
+            Just True -> ForceHash
+            Just False -> ForceNoHash
+            Nothing -> PreferHash
+      return $ Just (verbose, Options defaultDecodeOptions {decodeOptionsTarget = file} force generateHash toStdout)
     ParseError -> do
       printHelp
       exitFailure
@@ -102,7 +110,7 @@
 printHelp = do
   name <- getProgName
   Utf8.hPutStrLn stderr $ unlines [
-      "Usage: " ++ name ++ " [ --silent ] [ --force | -f ] [ PATH ] [ - ]"
+      "Usage: " ++ name ++ " [ --silent ] [ --force | -f ] [ --[no-]hash ] [ PATH ] [ - ]"
     , "       " ++ name ++ " --version"
     , "       " ++ name ++ " --numeric-version"
     , "       " ++ name ++ " --help"
@@ -112,7 +120,7 @@
 hpack verbose options = hpackResult options >>= printResult verbose
 
 defaultOptions :: Options
-defaultOptions = Options defaultDecodeOptions NoForce False
+defaultOptions = Options defaultDecodeOptions NoForce PreferHash False
 
 setTarget :: FilePath -> Options -> Options
 setTarget target options@Options{..} =
@@ -157,41 +165,76 @@
 printWarnings :: [String] -> IO ()
 printWarnings = mapM_ $ Utf8.hPutStrLn stderr . ("WARNING: " ++)
 
-mkStatus :: [String] -> Version -> CabalFile -> Status
-mkStatus new v (CabalFile mOldVersion mHash old) = case (mOldVersion, mHash) of
-  (_, _) | old == new -> OutputUnchanged
-  (Nothing, _) -> ExistingCabalFileWasModifiedManually
-  (Just oldVersion, _) | oldVersion < makeVersion [0, 20, 0] -> Generated
-  (_, Nothing) -> ExistingCabalFileWasModifiedManually
-  (Just oldVersion, Just hash)
-    | v < oldVersion -> AlreadyGeneratedByNewerHpack
-    | sha256 (unlines old) /= hash -> ExistingCabalFileWasModifiedManually
-    | otherwise -> Generated
+mkStatus :: CabalFile -> CabalFile -> Status
+mkStatus new@(CabalFile _ mNewVersion mNewHash _) existing@(CabalFile _ mExistingVersion _ _)
+  | new `hasSameContent` existing = OutputUnchanged
+  | otherwise = case mExistingVersion of
+      Nothing -> ExistingCabalFileWasModifiedManually
+      Just _
+        | mNewVersion < mExistingVersion -> AlreadyGeneratedByNewerHpack
+        | isJust mNewHash && hashMismatch existing -> ExistingCabalFileWasModifiedManually
+        | otherwise -> Generated
 
+hasSameContent :: CabalFile -> CabalFile -> Bool
+hasSameContent (CabalFile cabalVersionA _ _ a) (CabalFile cabalVersionB _ _ b) = cabalVersionA == cabalVersionB && a == b
+
+hashMismatch :: CabalFile -> Bool
+hashMismatch cabalFile = case cabalFileHash cabalFile of
+  Nothing -> False
+  Just hash -> hash /= calculateHash cabalFile
+
+calculateHash :: CabalFile -> Hash
+calculateHash (CabalFile cabalVersion _ _ body) = sha256 (unlines $ cabalVersion ++ body)
+
 hpackResult :: Options -> IO Result
 hpackResult = hpackResultWithVersion version
 
 hpackResultWithVersion :: Version -> Options -> IO Result
-hpackResultWithVersion v (Options options force toStdout) = do
-  DecodeResult pkg cabalVersion cabalFile warnings <- readPackageConfig options >>= either die return
-  oldCabalFile <- readCabalFile cabalFile
-  let
-    body = renderPackage (maybe [] cabalFileContents oldCabalFile) pkg
-    withoutHeader = cabalVersion ++ body
+hpackResultWithVersion v (Options options force generateHashStrategy toStdout) = do
+  DecodeResult pkg (lines -> cabalVersion) cabalFileName warnings <- readPackageConfig options >>= either die return
+  mExistingCabalFile <- readCabalFile cabalFileName
   let
+    newCabalFile = makeCabalFile generateHashStrategy mExistingCabalFile cabalVersion v pkg
+
     status = case force of
       Force -> Generated
-      NoForce -> maybe Generated (mkStatus (lines withoutHeader) v) oldCabalFile
+      NoForce -> maybe Generated (mkStatus newCabalFile) mExistingCabalFile
+
   case status of
-    Generated -> do
-      let hash = sha256 withoutHeader
-          out  = cabalVersion ++ header (decodeOptionsTarget options) v hash ++ body
-      if toStdout
-        then Utf8.putStr out
-        else Utf8.writeFile cabalFile out
+    Generated -> writeCabalFile options toStdout cabalFileName newCabalFile
     _ -> return ()
+
   return Result {
-      resultWarnings = warnings
-    , resultCabalFile = cabalFile
-    , resultStatus = status
-    }
+    resultWarnings = warnings
+  , resultCabalFile = cabalFileName
+  , resultStatus = status
+  }
+
+writeCabalFile :: DecodeOptions -> Bool -> FilePath -> CabalFile -> IO ()
+writeCabalFile options toStdout name cabalFile = do
+  write . unlines $ renderCabalFile (decodeOptionsTarget options) cabalFile
+  where
+    write = if toStdout then Utf8.putStr else Utf8.writeFile name
+
+makeCabalFile :: GenerateHashStrategy -> Maybe CabalFile -> [String] -> Version -> Package -> CabalFile
+makeCabalFile strategy mExistingCabalFile cabalVersion v pkg = cabalFile
+  where
+    cabalFile = CabalFile cabalVersion (Just v) hash body
+
+    hash
+      | shouldGenerateHash mExistingCabalFile strategy = Just $ calculateHash cabalFile
+      | otherwise = Nothing
+
+    body = lines $ renderPackage (maybe [] cabalFileContents mExistingCabalFile) pkg
+
+shouldGenerateHash :: Maybe CabalFile -> GenerateHashStrategy -> Bool
+shouldGenerateHash mExistingCabalFile strategy = case (strategy, mExistingCabalFile) of
+  (ForceHash, _) -> True
+  (ForceNoHash, _) -> False
+  (PreferHash, Nothing) -> True
+  (PreferNoHash, Nothing) -> False
+  (_, Just CabalFile {cabalFileHash = Nothing}) -> False
+  (_, Just CabalFile {cabalFileHash = Just _}) -> True
+
+renderCabalFile :: FilePath -> CabalFile -> [String]
+renderCabalFile file (CabalFile cabalVersion hpackVersion hash body) = cabalVersion ++ header file hpackVersion hash ++ body
diff --git a/src/Hpack/CabalFile.hs b/src/Hpack/CabalFile.hs
--- a/src/Hpack/CabalFile.hs
+++ b/src/Hpack/CabalFile.hs
@@ -16,7 +16,8 @@
 makeVersion v = Version v []
 
 data CabalFile = CabalFile {
-  cabalFileHpackVersion :: Maybe Version
+  cabalFileCabalVersion :: [String]
+, cabalFileHpackVersion :: Maybe Version
 , cabalFileHash :: Maybe Hash
 , cabalFileContents :: [String]
 } deriving (Eq, Show)
@@ -25,13 +26,13 @@
 readCabalFile cabalFile = fmap parse <$> tryReadFile cabalFile
   where
     parse :: String -> CabalFile
-    parse (splitHeader -> (h, c)) = CabalFile (extractVersion h) (extractHash h) c
+    parse (splitHeader -> (cabalVersion, h, c)) = CabalFile cabalVersion (extractVersion h) (extractHash h) c
 
-    splitHeader :: String -> ([String], [String])
+    splitHeader :: String -> ([String], [String], [String])
     splitHeader (removeGitConflictMarkers . lines -> c) =
       case span (not . isComment) c of
         (cabalVersion, xs) -> case span isComment xs of
-          (header, body) -> (header, cabalVersion ++ dropWhile null body)
+          (header, body) -> (cabalVersion, header, dropWhile null body)
 
     isComment = ("--" `isPrefixOf`)
 
diff --git a/src/Hpack/Config.hs b/src/Hpack/Config.hs
--- a/src/Hpack/Config.hs
+++ b/src/Hpack/Config.hs
@@ -39,6 +39,7 @@
 , section
 , Package(..)
 , Dependencies(..)
+, DependencyInfo(..)
 , VersionConstraint(..)
 , DependencyVersion(..)
 , SourceDependency(..)
diff --git a/src/Hpack/Options.hs b/src/Hpack/Options.hs
--- a/src/Hpack/Options.hs
+++ b/src/Hpack/Options.hs
@@ -1,6 +1,9 @@
 {-# LANGUAGE LambdaCase #-}
 module Hpack.Options where
 
+import           Control.Applicative
+import           Control.Monad
+import           Data.Maybe
 import           System.FilePath
 import           System.Directory
 
@@ -16,6 +19,7 @@
 data ParseOptions = ParseOptions {
   parseOptionsVerbose :: Verbose
 , parseOptionsForce :: Force
+, parseOptionsHash :: Maybe Bool
 , parseOptionsToStdout :: Bool
 , parseOptionsTarget :: FilePath
 } deriving (Eq, Show)
@@ -30,18 +34,30 @@
       file <- expandTarget defaultTarget target
       let
         options
-          | toStdout = ParseOptions NoVerbose Force toStdout file
-          | otherwise = ParseOptions verbose force toStdout file
+          | toStdout = ParseOptions NoVerbose Force hash toStdout file
+          | otherwise = ParseOptions verbose force hash toStdout file
       return (Run options)
     Left err -> return err
     where
       silentFlag = "--silent"
       forceFlags = ["--force", "-f"]
+      hashFlag = "--hash"
+      noHashFlag = "--no-hash"
 
-      flags = silentFlag : forceFlags
+      flags = hashFlag : noHashFlag : silentFlag : forceFlags
 
+      verbose :: Verbose
       verbose = if silentFlag `elem` args then NoVerbose else Verbose
+
+      force :: Force
       force = if any (`elem` args) forceFlags then Force else NoForce
+
+      hash :: Maybe Bool
+      hash = listToMaybe . reverse $ mapMaybe parse args
+        where
+          parse :: String -> Maybe Bool
+          parse t = True <$ guard (t == hashFlag) <|> False <$ guard (t == noHashFlag)
+
       ys = filter (`notElem` flags) args
 
       targets :: Either ParseResult (Maybe FilePath, Bool)
diff --git a/src/Hpack/Render.hs b/src/Hpack/Render.hs
--- a/src/Hpack/Render.hs
+++ b/src/Hpack/Render.hs
@@ -45,7 +45,6 @@
 import           Hpack.Config
 import           Hpack.Render.Hints
 import           Hpack.Render.Dsl
-import           Hpack.Syntax.Dependencies
 
 renderPackage :: [String] -> Package -> String
 renderPackage oldCabalFile = renderPackageWith settings alignment formattingHintsFieldOrder formattingHintsSectionsFieldOrder
diff --git a/test/Hpack/CabalFileSpec.hs b/test/Hpack/CabalFileSpec.hs
--- a/test/Hpack/CabalFileSpec.hs
+++ b/test/Hpack/CabalFileSpec.hs
@@ -9,9 +9,15 @@
 
 import           Paths_hpack (version)
 
+import           Hpack.Util (Hash)
+import           Data.Version (Version)
 import           Hpack (header)
+
 import           Hpack.CabalFile
 
+mkHeader :: FilePath -> Version -> Hash -> String
+mkHeader p v hash = unlines $ header p (Just v) (Just hash)
+
 spec :: Spec
 spec = do
   describe "readCabalFile" $ do
@@ -21,13 +27,13 @@
 
     it "includes hash" $ do
       inTempDirectory $ do
-        writeFile file $ header "package.yaml" version hash
-        readCabalFile file `shouldReturn` Just (CabalFile (Just version) (Just hash) [])
+        writeFile file $ mkHeader "package.yaml" version hash
+        readCabalFile file `shouldReturn` Just (CabalFile [] (Just version) (Just hash) [])
 
     it "accepts cabal-version at the beginning of the file" $ do
       inTempDirectory $ do
-        writeFile file $ ("cabal-version: 2.2\n" ++ header "package.yaml" version hash)
-        readCabalFile file `shouldReturn` Just (CabalFile (Just version) (Just hash) ["cabal-version: 2.2"])
+        writeFile file $ ("cabal-version: 2.2\n" ++ mkHeader "package.yaml" version hash)
+        readCabalFile file `shouldReturn` Just (CabalFile ["cabal-version: 2.2"] (Just version) (Just hash) [])
 
   describe "extractVersion" $ do
     it "extracts Hpack version from a cabal file" $ do
diff --git a/test/Hpack/OptionsSpec.hs b/test/Hpack/OptionsSpec.hs
--- a/test/Hpack/OptionsSpec.hs
+++ b/test/Hpack/OptionsSpec.hs
@@ -18,10 +18,10 @@
 
     context "by default" $ do
       it "returns Run" $ do
-        parseOptions defaultTarget [] `shouldReturn` Run (ParseOptions Verbose NoForce False defaultTarget)
+        parseOptions defaultTarget [] `shouldReturn` Run (ParseOptions Verbose NoForce Nothing False defaultTarget)
 
       it "includes target" $ do
-        parseOptions defaultTarget ["foo.yaml"] `shouldReturn` Run (ParseOptions Verbose NoForce False "foo.yaml")
+        parseOptions defaultTarget ["foo.yaml"] `shouldReturn` Run (ParseOptions Verbose NoForce Nothing False "foo.yaml")
 
       context "with superfluous arguments" $ do
         it "returns ParseError" $ do
@@ -29,19 +29,31 @@
 
       context "with --silent" $ do
         it "sets optionsVerbose to NoVerbose" $ do
-          parseOptions defaultTarget ["--silent"] `shouldReturn` Run (ParseOptions NoVerbose NoForce False defaultTarget)
+          parseOptions defaultTarget ["--silent"] `shouldReturn` Run (ParseOptions NoVerbose NoForce Nothing False defaultTarget)
 
       context "with --force" $ do
         it "sets optionsForce to Force" $ do
-          parseOptions defaultTarget ["--force"] `shouldReturn` Run (ParseOptions Verbose Force False defaultTarget)
+          parseOptions defaultTarget ["--force"] `shouldReturn` Run (ParseOptions Verbose Force Nothing False defaultTarget)
 
       context "with -f" $ do
         it "sets optionsForce to Force" $ do
-          parseOptions defaultTarget ["-f"] `shouldReturn` Run (ParseOptions Verbose Force False defaultTarget)
+          parseOptions defaultTarget ["-f"] `shouldReturn` Run (ParseOptions Verbose Force Nothing False defaultTarget)
 
+      context "when determining parseOptionsHash" $ do
+
+        it "assumes True on --hash" $ do
+          parseOptions defaultTarget ["--hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just True) False defaultTarget)
+
+        it "assumes False on --no-hash" $ do
+          parseOptions defaultTarget ["--no-hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just False) False defaultTarget)
+
+        it "gives last occurrence precedence" $ do
+          parseOptions defaultTarget ["--no-hash", "--hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just True) False defaultTarget)
+          parseOptions defaultTarget ["--hash", "--no-hash"] `shouldReturn` Run (ParseOptions Verbose NoForce (Just False) False defaultTarget)
+
       context "with -" $ do
         it "sets optionsToStdout to True, implies Force and NoVerbose" $ do
-          parseOptions defaultTarget ["-"] `shouldReturn` Run (ParseOptions NoVerbose Force True defaultTarget)
+          parseOptions defaultTarget ["-"] `shouldReturn` Run (ParseOptions NoVerbose Force Nothing True defaultTarget)
 
         it "rejects - for target" $ do
           parseOptions defaultTarget ["-", "-"] `shouldReturn` ParseError
diff --git a/test/Hpack/RenderSpec.hs b/test/Hpack/RenderSpec.hs
--- a/test/Hpack/RenderSpec.hs
+++ b/test/Hpack/RenderSpec.hs
@@ -10,7 +10,6 @@
 import           Hpack.Config hiding (package)
 import           Hpack.Render.Dsl
 import           Hpack.Render
-import           Hpack.Syntax.Dependencies
 
 library :: Library
 library = Library Nothing [] [] [] [] []
diff --git a/test/HpackSpec.hs b/test/HpackSpec.hs
--- a/test/HpackSpec.hs
+++ b/test/HpackSpec.hs
@@ -6,7 +6,6 @@
 import qualified Prelude as Prelude
 
 import           Control.DeepSeq
-import           Data.List
 
 import           Hpack.Config
 import           Hpack.CabalFile
@@ -17,94 +16,139 @@
 
 spec :: Spec
 spec = do
-  describe "hpackResult" $ do
-    context "with existing cabal file" $ around_ inTempDirectory $ before_ (writeFile packageConfig "name: foo") $ do
-      let
-        file = "foo.cabal"
+  describe "header" $ do
+    it "generates header" $ do
+      header "foo.yaml" Nothing Nothing `shouldBe` [
+          "-- This file has been generated from foo.yaml by hpack."
+        , "--"
+        , "-- see: https://github.com/sol/hpack"
+        , ""
+        ]
 
-        hpackWithVersion v = hpackResultWithVersion v defaultOptions
-        hpack = hpackResult defaultOptions
-        hpackForce = hpackResult defaultOptions {optionsForce = Force}
+    context "with hpack version" $ do
+      it "includes hpack version" $ do
+        header "foo.yaml" (Just $ makeVersion [0,34,0]) Nothing `shouldBe` [
+            "-- This file has been generated from foo.yaml by hpack version 0.34.0."
+          , "--"
+          , "-- see: https://github.com/sol/hpack"
+          , ""
+          ]
 
-        generated = Result [] file Generated
-        modifiedManually = Result [] file ExistingCabalFileWasModifiedManually
-        outputUnchanged = Result [] file OutputUnchanged
-        alreadyGeneratedByNewerHpack = Result [] file AlreadyGeneratedByNewerHpack
+    context "with hash" $ do
+      it "includes hash" $ do
+        header "foo.yaml" Nothing (Just "some-hash") `shouldBe` [
+            "-- This file has been generated from foo.yaml by hpack."
+          , "--"
+          , "-- see: https://github.com/sol/hpack"
+          , "--"
+          , "-- hash: some-hash"
+          , ""
+          ]
 
-      context "when cabal file was created manually" $ do
-        it "does not overwrite existing cabal file" $ do
-          let existing = "some existing cabal file"
-          writeFile file existing
-          hpack `shouldReturn` modifiedManually
+  describe "renderCabalFile" $ do
+    it "is inverse to readCabalFile" $ do
+      expected <- lines <$> readFile "hpack.cabal"
+      Just c <- readCabalFile "hpack.cabal"
+      renderCabalFile "package.yaml" c `shouldBe` expected
+
+  describe "hpackResult" $ around_ inTempDirectory $ before_ (writeFile packageConfig "name: foo") $ do
+    let
+      file = "foo.cabal"
+
+      hpackWithVersion v = hpackResultWithVersion (makeVersion v) defaultOptions
+      hpackWithStrategy strategy = hpackResult defaultOptions { optionsGenerateHashStrategy = strategy }
+      hpackForce = hpackResult defaultOptions {optionsForce = Force}
+
+      generated = Result [] file Generated
+      modifiedManually = Result [] file ExistingCabalFileWasModifiedManually
+      outputUnchanged = Result [] file OutputUnchanged
+      alreadyGeneratedByNewerHpack = Result [] file AlreadyGeneratedByNewerHpack
+
+      modifyPackageConfig = writeFile packageConfig $ unlines [
+          "name: foo"
+        , "version: 0.1.0"
+        ]
+
+      modifyCabalFile = do
+        xs <- readFile file
+        writeFile file $ xs ++ "foo\n"
+
+      manuallyCreateCabalFile = do
+        writeFile file "some existing cabal file"
+
+      doesNotGenerateHash :: HasCallStack => GenerateHashStrategy -> Spec
+      doesNotGenerateHash strategy = do
+        it "does not generate hash" $ do
+          hpackWithStrategy strategy `shouldReturn` generated
+          readFile file >>= (`shouldNotContain` "hash")
+
+      generatesHash :: HasCallStack => GenerateHashStrategy -> Spec
+      generatesHash strategy = do
+        it "generates hash" $ do
+          hpackWithStrategy strategy `shouldReturn` generated
+          readFile file >>= (`shouldContain` "hash")
+
+      doesNotOverwrite :: HasCallStack => GenerateHashStrategy -> Spec
+      doesNotOverwrite strategy = do
+        it "does not overwrite cabal file" $ do
+          existing <- readFile file
+          hpackWithStrategy strategy `shouldReturn` modifiedManually
           readFile file `shouldReturn` existing
 
-        context "with --force" $ do
-          it "overwrites existing cabal file" $ do
-            _ <- hpack
-            expected <- readFile file
-            writeFile file "some existing cabal file"
-            hpackForce `shouldReturn` generated
-            readFile file `shouldReturn` expected
+      with strategy item = context ("with " ++ show strategy) $ item strategy
 
-      context "when cabal file was created with hpack < 0.20.0" $ do
-        it "overwrites existing cabal file" $ do
-          _ <- hpack
-          expected <- readFile file
-          writeFile file "-- This file has been generated from package.yaml by hpack version 0.19.3."
-          hpack `shouldReturn` generated
-          readFile file `shouldReturn` expected
+    context "without an existing cabal file" $ do
+      with ForceHash generatesHash
+      with PreferHash generatesHash
+      with ForceNoHash doesNotGenerateHash
+      with PreferNoHash doesNotGenerateHash
 
-      context "when cabal file was created with hpack >= 0.20.0" $ do
-        context "when hash is missing" $ do
-          it "does not overwrite existing cabal file" $ do
-            let existing = "-- This file has been generated from package.yaml by hpack version 0.20.0."
-            writeFile file existing
-            hpack `shouldReturn` modifiedManually
-            readFile file `shouldReturn` existing
+    context "with an existing cabal file" $ do
+      context "without a hash" $ before_ (hpackWithStrategy ForceNoHash >> modifyPackageConfig) $ do
+        with ForceHash generatesHash
+        with PreferHash doesNotGenerateHash
+        with ForceNoHash doesNotGenerateHash
+        with PreferNoHash doesNotGenerateHash
 
-          context "when only the the cabal file header changed" $ do
-            it "does not complain if it's newer" $ do
-              hpack `shouldReturn` generated
-              let removeHash = unlines . filter (not . isInfixOf "hash") . lines
-              readFile file >>= writeFile file . removeHash
-              hpack `shouldReturn` outputUnchanged
+      context "with a hash" $ before_ (hpackWithStrategy ForceHash >> modifyPackageConfig) $ do
+        with ForceHash generatesHash
+        with PreferHash generatesHash
+        with ForceNoHash doesNotGenerateHash
+        with PreferNoHash generatesHash
 
-        context "when hash is present" $ do
-          context "when exsting cabal file was generated with a newer version of hpack" $ do
-            it "does not overwrite existing cabal file" $ do
-              writeFile packageConfig $ unlines [
-                  "name: foo"
-                , "version: 0.1.0"
-                ]
-              _ <- hpackWithVersion (makeVersion [0,22,0])
-              old <- readFile file
+        context "with manual modifications" $ before_ modifyCabalFile $ do
+          with ForceHash doesNotOverwrite
+          with PreferHash doesNotOverwrite
+          with ForceNoHash doesNotGenerateHash
+          with PreferNoHash doesNotOverwrite
 
-              writeFile packageConfig $ unlines [
-                  "name: foo"
-                , "version: 0.2.0"
-                ]
+      context "when created manually" $ before_ manuallyCreateCabalFile $ do
+        with ForceHash doesNotOverwrite
+        with PreferHash doesNotOverwrite
+        with ForceNoHash doesNotOverwrite
+        with PreferNoHash doesNotOverwrite
 
-              hpackWithVersion (makeVersion [0,20,0]) `shouldReturn` alreadyGeneratedByNewerHpack
-              readFile file `shouldReturn` old
+        context "with --force" $ do
+          it "overwrites cabal file" $ do
+            hpackForce `shouldReturn` generated
 
-          context "when cabal file was modified manually" $ do
-            it "does not overwrite existing cabal file" $ do
-              _ <- hpack
-              old <- readFile file
-              let modified = old ++ "foo\n"
-              writeFile file modified
-              _ <- hpack
-              readFile file `shouldReturn` modified
+      context "when generated with a newer version of hpack" $ do
+        it "does not overwrite cabal file" $ do
+          _ <- hpackWithVersion [0,22,0]
+          old <- readFile file
+          modifyPackageConfig
+          hpackWithVersion [0,20,0] `shouldReturn` alreadyGeneratedByNewerHpack
+          readFile file `shouldReturn` old
 
-          context "when only the hpack version in the cabal file header changed" $ do
-            it "does not overwrite existing cabal file" $ do
-              _ <- hpackWithVersion (makeVersion [0,20,0])
-              old <- readFile file
-              hpack `shouldReturn` outputUnchanged
-              readFile file `shouldReturn` old
+      context "when only the hpack version in the cabal file header changed" $ do
+        it "does not overwrite cabal file" $ do
+          _ <- hpackWithVersion [0,22,0]
+          old <- readFile file
+          hpackWithVersion [0,30,0] `shouldReturn` outputUnchanged
+          readFile file `shouldReturn` old
 
-            it "does not complain if it's newer" $ do
-              _ <- hpackWithVersion (makeVersion [999,999,0])
-              old <- readFile file
-              hpack `shouldReturn` outputUnchanged
-              readFile file `shouldReturn` old
+        it "does not complain if it's newer" $ do
+          _ <- hpackWithVersion [0,22,0]
+          old <- readFile file
+          hpackWithVersion [0,20,0] `shouldReturn` outputUnchanged
+          readFile file `shouldReturn` old
