diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 0.2.2 (2019-07-06)
+- run hlint before git tag
+- relax force sdist when no existing tarball
+- show git diff to warn project dirty
+
 ## 0.2.1 (2019-06-24)
 - fix creation of published symlink lockfile
 - tagdist before `cabal upload` if no tarball
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -24,8 +24,8 @@
 
 main :: IO ()
 main =
-  simpleCmdArgs (Just version) "HacKaGe Release workflow"
-  "A tool to help Hackage maintainers with releasing packages" $
+  simpleCmdArgs (Just version) "Hackage Release tool"
+  "'Hackager' is a package release tool for easy Hackage workflow" $
   subcommands
   [ Subcommand "tagdist" "'git tag' version and 'cabal sdist' tarball" $
     tagDistCmd <$> forceOpt "Move existing tag"
@@ -42,6 +42,9 @@
 
 tagDistCmd :: Bool -> IO ()
 tagDistCmd force = do
+  mhlint <- findExecutable "hlint"
+  when (isJust mhlint) $ cmd_ "hlint" ["."]
+  git_ "diff" []
   pkgid <- getPackageId
   checkNotPublished pkgid
   let tag = packageVersion pkgid
@@ -54,8 +57,8 @@
   unless distOk $ do
     putStrLn "Resetting tag"
     if force
-    then git_ "tag" ["--force", tag, fromJust tagHash]
-    else git_ "tag" ["--delete", tag]
+      then git_ "tag" ["--force", tag, fromJust tagHash]
+      else git_ "tag" ["--delete", tag]
 
 checkNotPublished :: PackageIdentifier -> IO ()
 checkNotPublished pkgid = do
@@ -68,11 +71,10 @@
   let ver = packageVersion pkgid
   let target = "dist" </> showPkgId pkgid <.> ".tar.gz"
   haveTarget <- doesFileExist target
-  if haveTarget
-    then if force
-         then removeFile target
-         else error' $ target <> " exists already!"
-    else when force $ error' "Target does not exist, please use 'dist' command"
+  when haveTarget $
+    if force
+    then removeFile target
+    else error' $ target <> " exists already!"
   cwd <- getCurrentDirectory
   withTempDirectory "tmp-sdist" $ do
     git_ "clone" ["-q", "--no-checkout", "..", "."]
@@ -80,7 +82,6 @@
     cabal_ "check" []
     cabal_ "configure" []
     -- cabal_ "build" []
-    cmd_ "hlint" ["."]
     distOk <- cmdBool "cabal" ["sdist"]
     when distOk $ renameFile target (cwd </> target)
     return distOk
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,17 +4,17 @@
 [![GPL-3 license](https://img.shields.io/badge/license-GPL--3-blue.svg)](LICENSE)
 [![Build status](https://secure.travis-ci.org/juhp/hkgr.svg)](https://travis-ci.org/juhp/hkgr)
 
-`hkgr` (pronounced "Hackager") is a tool for making releases of
+`hkgr` (pronounced "hackager") is a tool for making releases of
 Haskell packages on Hackage.
 
 ## Usage
 
 ```
 $ hkgr
-HacKaGe Release workflow
+Hackage Release tool
 
 Usage: hkgr [--version] COMMAND
-  A tool to help Hackage maintainers with releasing packages
+  'Hackager' is a tool for easy Hackage package release workflow
 
 Available options:
   -h,--help                Show this help text
@@ -29,13 +29,70 @@
   version                  Show the package version from .cabal file
 ```
 
-## Example
+## Explanation
+
+You are preparing for a release...
+
+So you commit changes to your package and push them to check CI results:
+
 ```
 $ git commit -m "new release"
 $ git push
+```
+
+
+### tagdist
+Now you want to make a dist tarball, which is done from a git tag:
+```
 $ hkgr tagdist
+```
+The `tagdist` command first reads the current package version
+(from the `.cabal` file in the current directory), and uses that to `git tag`.
+It then runs `cabal sdist` from a temporary pristine checkout of the tag
+to generate the dist tarball.
+
+If the tag already exists (eg if you already ran `tagdist` earlier),
+and you need to add commits to the release
+you can use `--force` to move the tag to the latest commit
+and generate a new tarball off that,
+otherwise `tagdist` refuses to run again to prevent accidently overwriting
+the tag and dist tarball.
+
+One should not be able to `tagdist` on an already published
+(ie released) version.
+
+(If sdist fails for some reason then hkgr tries to reset the tag.)
+
+### upload
+If all is good, it's time for a candidate release:
+
+```
 $ hkgr upload
+```
+This uploads a candidate dist tarball to Hackage: this can be repeated.
+
+Haddock draft documentation can also be uploaded if desired:
+```
 $ hkgr upload-haddock
+```
+
+### publish
+Once you are happy, you can release to Hackage:
+
+```
 $ hkgr publish
+```
+
+If it succeeds then hkgr creates a "published lockfile" in `dist/`,
+and the git tag is pushed to origin.
+
+(Then hkgr will refuse to do further commands on the released version.)
+
+Optionally one can publish haddock docs:
+```
 $ hkgr publish-haddock
 ```
+
+## Requirements
+
+hkgr uses `cabal-install`, `git`, and also `hlint` if available.
diff --git a/hkgr.cabal b/hkgr.cabal
--- a/hkgr.cabal
+++ b/hkgr.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.0
 name:                hkgr
-version:             0.2.1
+version:             0.2.2
 synopsis:            Simple Hackage release workflow for package maintainers
 description:
             Hkgr (pronouced "Hackager") is a tool to help make new releases of
