diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,35 @@
 # Changelog
 
+## 1.3.3 (2023-10-19)
+- 'bump': add --dry-run
+- 'copr': track pkg name to output build results url on failure
+- 'create-review','update-review': prompt to offer scratch build (#43)
+- 'diff': allow origin as alias for origin/<branch>
+- 'import': encode url from bz comment if needed (#40)
+- 'import': prefix bug# with rhbz in commit (#38)
+- 'install': add --no-build to install existing built rpms
+- 'parallel': --delay to override default inter-package pause [default 3s]
+- 'parallel': use pkg name in changelog instead of nvr
+- 'parallel': print if no more layers
+- 'parallel': try to make Bodhi update prompt more obvious
+- 'request-repo': avoid head crash on firstname (#45)
+- 'request-repo': no longer post request url to avoid duplication
+- 'scratch': with --exclude-arch respect ExcludeArch: fields
+- 'unpushed': add --bump
+- 'unpushed': output improvements for --latest and dead.package/missing
+- 'update-sources': alias for "update-version --source-only"
+- 'update-version': only warn about branch if dist-git
+- 'update-version': rpm prep with --nodeps
+- 'update-version': take .gpg and .tgz file for lookaside archive!
+- Krb: loop fkinit until okay
+- Main: --dry-run options now better described
+- RpmBuild: prevent srpm creation from being interrupted (eg ctrl-c)
+- gitFetchSilent: use \r to hide "git fetching..."
+- kojiBuild: remove "Take info: " prefix before koji task url
+- kojiWatchTask: do not hardcode koji-tool path
+- pkgNameVerRel: use fedpkg to determine correct %autorelease (#39)
+- refPrompt: do not trim input for more precision
+
 ## 1.3.2 (2023-05-30)
 - prompts now support line-editting thanks to simple-prompt-0.2 using haskeline
 - 'parallel', 'sort', 'graph': use getDynSourcesMacros
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@
 
 One can change the branch of one or more packages:
 ```
-$ fbrnch switch f38 [package] ...
+$ fbrnch switch f39 [package] ...
 ```
 
 You can also git pull over packages:
@@ -79,10 +79,10 @@
 ```
 
 ### Commit, Merging and Building in Koji
-The update-version command helps with updating a package
-after editing the spec file to a newer version:
+The update-sources and update-version commands can help with updating
+a package after editing the spec file to a newer version:
 ```
-$ fbrnch update-version
+$ fbrnch update-sources
 ```
 which will download the new tarball and upload it, etc.
 
@@ -97,9 +97,9 @@
 
 You can merge branches with:
 ```
-$ fbrnch merge f37 package
+$ fbrnch merge f38 package
 ```
-which will offer to merge f38 (or up to a git hash you choose) into f37.
+which will offer to merge f39 (or up to a git hash you choose) into f38.
 
 Merging can also be done together with building:
 ```
@@ -155,7 +155,7 @@
 
 Locally build and install:
 ```
-$ fbrnch install package1 package2 package3 ...
+$ fbrnch install package1 package2/ package3 ...
 ```
 
 You can use:
@@ -168,7 +168,7 @@
 ```
 $ fbrnch rename-rawhide [package]
 ```
-to rename an old master branch locally to rawhide.
+to rename an old local master branch to rawhide.
 
 ### Parallel building
 fbrnch can sort packages automatically and build them in parallel
@@ -178,16 +178,17 @@
 ```
 $ fbrnch parallel --sidetag rawhide pkg-x pkg-y pkg-z pkg-xy pkg-xy-z
 ```
-builds a list of packages in a sidetag (generating it if needed)
+builds a list of packages in a sidetag (generating it if no sidetags exist)
 in parallel ordered by build dependencies.
 
-When building for a branch, merging from newer branch will be offered
+When building for a branch, merging from the next newer branch will be offered
 unless using `--no-merge`
-(though you may prefer to run `fbrnch merge <branch> ...` first instead).
+(then you may prefer to run `fbrnch merge <branch> ...` first instead).
 
 Except for rawhide using a --sidetag or --target is required.
 If you have more than one active sidetag for a branch,
 you can select one using `--target`.
+They can be listed with `fbrnch sidetags`.
 
 After parallel building you can create a Bodhi update from the sidetag.
 
@@ -200,16 +201,18 @@
 ```
 $ fbrnch create-review [my-new-package]
 ```
-This will create (or update) an srpm, run rpmlint,
-then upload it to fedorapeople, perform a scratch build,
-and open a Review Request in Bugzilla (similar to fedora-create-review).
+This will create an srpm (or update it if the spec file is newer), run rpmlint,
+optionally perform a scratch build, then upload the spec and srpm to
+fedorapeople, and open a Review Request in Bugzilla
+(similar to fedora-create-review).
 
 #### Update a package review
 ```
 $ fbrnch update-review [my-new-package]
 ```
 Similar to create-review: it uploads the updated files to fedorapeople
-and posts the updated package urls to the open package review.
+and posts the updated package urls to the open package review
+with an optional scratch build.
 
 #### List open package reviews
 To list one's open package reviews:
@@ -257,10 +260,14 @@
 
 Here is an "extreme" [example](https://github.com/fedora-haskell/haskell-language-server/blob/main/build.sh) of a script using `fbrnch copr` to do multiple staggered builds.
 
+## Help
+`$ fbrnch --version`
 ```
-$ fbrnch --version
-1.3.2
-$ fbrnch --help
+1.3.3
+```
+
+`$ fbrnch --help`
+```
 Fedora branch building tool
 
 Usage: fbrnch [--version] COMMAND
@@ -290,6 +297,7 @@
   scratch                  Scratch build package in Koji
   scratch-aarch64          Koji aarch64 scratch build of package
   scratch-x86_64           Koji x86_64 scratch build of package
+  update-sources           Download and update newer sources
   update-version           Update package in dist-git to newer version
   sort                     Sort packages in build dependency order
   prep                     Prep sources
@@ -330,6 +338,9 @@
   move-artifacts           Move old rpm artifacts into rpmbuild dirs
 ```
 
+Use `fbrnch <cmd> --help` to get specific help about each of the above commands
+and their options.
+
 ## Installation
 fbrnch is packaged in Fedora: `sudo dnf install fbrnch`.
 
@@ -340,11 +351,11 @@
 
 3. Then either:
 
-a) using stack (probably 2.3 or later): `stack install`
+a) using stack: `stack install`
 
 or
 
-b) with cabal-install (probably 2.4 or later) and cabal-rpm:
+b) with cabal-install and cabal-rpm:
 
 ```
 $ cabal-rpm builddep
@@ -410,16 +421,16 @@
 <https://bugzilla.redhat.com/userprefs.cgi?tab=apikey>.
 
 ## Known issues
-- parallel builds will push local package commits without asking
 - currently it only checks if already built by NVR not githash
+- parallel and sort, etc do not take pkgconfig() and other meta() deps into
+  account yet (this should be fixed soon in rpmbuild-order)
+
+## To do
 - authentication is not implemented yet natively for Koji, Bodhi, Pagure
   (and source upload)
   - so python clients are used for "writing"
     (specifically koji, bodhi-client, fedpkg),
     but all queries are done directly by Web APIs for speed and control.
-- https checkouts are currently treated as anonymous git checkouts
-- parallel and sort, etc do not take pkgconfig() and other meta() deps into
-  account yet (this will be fixed in rpmbuild-order)
 
 ## Motivation, history, talks
 This project started off as a simple tool to build a package across branches
diff --git a/fbrnch.cabal b/fbrnch.cabal
--- a/fbrnch.cabal
+++ b/fbrnch.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.0
 name:                fbrnch
-version:             1.3.2
+version:             1.3.3
 synopsis:            Fedora packager tool to build package branches
 description:
             fbrnch (fedora branch) is a convenient packaging tool for
diff --git a/src/Branches.hs b/src/Branches.hs
--- a/src/Branches.hs
+++ b/src/Branches.hs
@@ -65,7 +65,7 @@
 activeBranches :: [Branch] -> [String] -> [Branch]
 activeBranches active =
   -- newest branch first
-  reverse . sort . mapMaybe (readActiveBranch active)
+  reverseSort . mapMaybe (readActiveBranch active)
 
 fedoraBranches :: IO [String] -> IO [Branch]
 fedoraBranches mthd = do
@@ -159,7 +159,7 @@
     activeBrs <- getFedoraBranches
     forM_ brs $ \ br ->
           if active
-            then when (br `notElem` activeBrs) $
+            then unless (br `elem` activeBrs) $
                  error' $ show br +-+ "is not an active branch"
             else
             case br of
diff --git a/src/Cmd/Bump.hs b/src/Cmd/Bump.hs
--- a/src/Cmd/Bump.hs
+++ b/src/Cmd/Bump.hs
@@ -14,10 +14,11 @@
 
 -- FIXME --force
 -- FIXME --target
--- FIXME detect rpmautospec and add empty commit
-bumpPkgs :: Bool -> Maybe CommitOpt -> Maybe String -> (BranchesReq,[String]) -> IO ()
-bumpPkgs local mopt mclog =
-  withPackagesByBranches (boolHeader local) False (if local then cleanGit else cleanGitFetchActive)
+bumpPkgs :: Bool -> Bool -> Maybe CommitOpt -> Maybe String
+         -> (BranchesReq,[String]) -> IO ()
+bumpPkgs dryrun local mopt mclog =
+  withPackagesByBranches (boolHeader local) False
+  (if local then cleanGit else cleanGitFetchActive)
   AnyNumber bumpPkg
   where
     bumpPkg :: Package -> AnyBranch -> IO ()
@@ -34,10 +35,10 @@
         newnvr <- pkgNameVerRel' rbr spec
         moldnvr <-
           if local
-          then do
+          then
             withTempFile $ \tempfile -> do
-              git "show" ["origin:" ++ spec] >>= writeFile tempfile
-              pkgNameVerRel rbr tempfile
+            git "show" ["origin:" ++ spec] >>= writeFile tempfile
+            pkgNameVerRel rbr tempfile
           else
             case br of
               RelBranch rbr' ->
@@ -56,7 +57,7 @@
                       Just (CommitMsg msg) -> msg
                       _ -> "rebuild"
           autorelease <- isAutoRelease spec
-          unless autorelease $
+          unless (autorelease || dryrun) $
             cmd_ "rpmdev-bumpspec" ["-c", clmsg, spec]
           let copts =
                 case mopt of
@@ -67,5 +68,7 @@
                       -- FIXME reject amend if already pushed
                       CommitAmend -> ["--amend", "--no-edit"]
           -- FIXME quiet commit?
-          git_ "commit" $ "-a" : (if autorelease then ("--allow-empty" :) else id) copts
+          if dryrun
+            then putStrLn "would be bumped with commit"
+            else git_ "commit" $ "-a" : (if autorelease then ("--allow-empty" :) else id) copts
           else putStrLn "already bumped"
diff --git a/src/Cmd/Copr.hs b/src/Cmd/Copr.hs
--- a/src/Cmd/Copr.hs
+++ b/src/Cmd/Copr.hs
@@ -44,8 +44,14 @@
   if listchroots
     then mapM_ putStrLn chroots
     else
-    if null pkgs then
-      getPackageName "." >>= coprBuildPkg chroots False
+    if null pkgs then do
+      pkg <- do
+        dirpkg <- getPackageName "."
+        exists <- doesFileExist $ packageSpec dirpkg
+        if exists
+          then return dirpkg
+          else Package . takeBaseName <$> findSpecfile
+      coprBuildPkg chroots False pkg
     else
       mapM_ (\(n,p) -> withExistingDirectory p $ coprBuildPkg chroots (n>0) (Package p)) $ zip (reverse [0,length pkgs - 1]) pkgs
   where
@@ -85,33 +91,32 @@
               then generateSrpm Nothing spec -- FIXME: let distopt = ["--undefine", "dist"]
               else return spec
       case buildBy of
-        SingleBuild -> coprBuild dryrun project srpm buildroots
+        SingleBuild -> coprBuild dryrun project srpm pkg buildroots
         -- FIXME or default to secondary parallel to previous primary
         ValidateByRelease -> do
           let initialChroots =
                 let primaryArch = releaseArch $ head buildroots
                 in map pure $ filter (isArch primaryArch) buildroots
               remainingChroots = buildroots \\ concat initialChroots
-          staggerBuilds srpm initialChroots remainingChroots
+          staggerBuilds srpm pkg initialChroots remainingChroots
         ValidateByArch -> do
           let initialChroots =
                 let newestRelease = removeArch $ head buildroots
                 in map pure $ filter (newestRelease `isPrefixOf`) buildroots
               remainingChroots = buildroots \\ concat initialChroots
-          staggerBuilds srpm initialChroots remainingChroots
+          staggerBuilds srpm pkg initialChroots remainingChroots
         BuildByRelease -> do
-          let initialChroots = groupBy sameRelease buildroots
-              remainingChroots = buildroots \\ concat initialChroots
-          staggerBuilds srpm initialChroots remainingChroots
+          let releaseChroots = groupBy sameRelease buildroots
+          staggerBuilds srpm pkg releaseChroots []
       when morepkgs putNewLn
 
     removeArch relarch = init $ dropWhileEnd (/= '-') relarch
     takeArch = takeWhileEnd (/= '-')
 
-    staggerBuilds srpm initialChroots remainingChroots = do
-      mapM_ (coprBuild dryrun project srpm) initialChroots
+    staggerBuilds srpm pkg initialChroots remainingChroots = do
+      mapM_ (coprBuild dryrun project srpm pkg) initialChroots
       unless (null remainingChroots) $
-        coprBuild dryrun project srpm remainingChroots
+        coprBuild dryrun project srpm pkg remainingChroots
 
     releaseArch = takeWhileEnd (/= '-')
 
@@ -119,8 +124,6 @@
 
     sameRelease r1 r2 = removeArch r1 == removeArch r2
 
-    reverseSort = reverse . sort
-
 branchRelease :: Branch -> String
 branchRelease Rawhide = "fedora-rawhide"
 branchRelease (Fedora n) = "fedora-" ++ show n
@@ -150,9 +153,9 @@
     let config = parseIniFile ini iniparser
     return $ either error' record config
 
-coprBuild :: Bool -> String -> FilePath -> [String] -> IO ()
-coprBuild _ _ _ [] = error' "No chroots chosen"
-coprBuild dryrun project srpm buildroots = do
+coprBuild :: Bool -> String -> FilePath -> Package -> [String] -> IO ()
+coprBuild _ _ _ _ [] = error' "No chroots chosen"
+coprBuild dryrun project srpm pkg buildroots = do
   let chrootargs = mconcat [["-r", bldrt] | bldrt <- buildroots]
       buildargs = ["build", "--nowait"] ++ chrootargs ++ [project, srpm]
   putNewLn
@@ -162,8 +165,15 @@
     putStrLn output
     let bid = read $ last $ words $ last $ lines output
     ok <- timeIO $ coprWatchBuild bid Nothing
-    unless ok $
-      error' $ "Failed: copr" +-+ unwords buildargs
+    unless ok $ do
+      putStrLn $ "Failed: copr" +-+ unwords buildargs
+      -- FIXME determine which chroot(s) failed
+      username <- getUsername
+      -- eg 06482247
+      let zbid =
+            let s = show bid
+            in (if length s < 8 then ('0' :) else id) s
+      error' $ "https://download.copr.fedorainfracloud.org/results" +/+ username +/+ project +/+ head buildroots +/+ zbid ++ "-" ++ unPackage pkg
 
 -- FIXME idea: Maybe Seconds to increment sleep
 coprWatchBuild :: Int -> Maybe String -> IO Bool
diff --git a/src/Cmd/Diff.hs b/src/Cmd/Diff.hs
--- a/src/Cmd/Diff.hs
+++ b/src/Cmd/Diff.hs
@@ -77,6 +77,9 @@
                       wbexists <- checkIfRemoteBranchExists wbr
                       if wbexists
                         then return $ Just ["origin/" ++ brn]
+                        else
+                        if brn == "origin"
+                        then return $ Just ["origin/" ++ show br]
                         else do
                           putStrLn $ "no" +-+ show wbr +-+ "for" +-+ unPackage pkg
                           return Nothing
diff --git a/src/Cmd/Import.hs b/src/Cmd/Import.hs
--- a/src/Cmd/Import.hs
+++ b/src/Cmd/Import.hs
@@ -56,31 +56,42 @@
         putNewLn
         promptEnter "Press Enter to continue"
         let srpms = map (T.replace "/reviews//" "/reviews/") $ concatMap findSRPMs comments
-        when (null srpms) $ error "No srpm urls found!"
         mapM_ T.putStrLn srpms
-        let srpm = (head . filter isURI . filter (".src.rpm" `isSuffixOf`) . words . T.unpack . last) srpms
-        let srpmfile = takeFileName srpm
-        -- FIXME if havesrpm then print local filename
-        promptEnter $ "Press Enter to import" +-+ srpmfile
-        havesrpm <- doesFileExist srpmfile
-        unless havesrpm $
-          cmd_ "curl" ["--silent", "--show-error", "--remote-name", srpm]
-        krbTicket
-        fedpkg_ "import" [srpmfile]
-        git_ "commit" ["--message", "import #" ++ show bid]
-        nvr <- pkgNameVerRel' Rawhide (pkg <.> "spec")
-        promptEnter $ "Press Enter to push and build" +-+ nvr
-        gitPush True Nothing
-        -- FIXME build more branches
-        kojiBuildBranch "rawhide" (Package pkg) Nothing ["--fail-fast"]
-        putBugBuild False session bid nvr
-        existing <- fedoraBranchesNoRawhide (localBranches False)
-        when (null existing) $ do
-          brs <- getRequestedBranches [] breq
-          requestPkgBranches False False mock (Branches brs) (Package pkg)
+        case (filter (".src.rpm" `isSuffixOf`) . words . T.unpack . last) srpms of
+          [] -> error' "no srpm filename found"
+          srcrpms ->
+            case filter (isURI . maybeEncodeURI) srcrpms of
+              [] -> error "no valid srpm urls found"
+              [srpmurl] -> do
+                let srpmfile = takeFileName srpmurl
+                -- FIXME if havesrpm then print local filename
+                promptEnter $ "Press Enter to import" +-+ srpmfile
+                havesrpm <- doesFileExist srpmfile
+                unless havesrpm $
+                  cmd_ "curl" ["--silent", "--show-error", "--remote-name", srpmurl]
+                krbTicket
+                fedpkg_ "import" [srpmfile]
+                git_ "commit" ["--message", "import rhbz#" ++ show bid]
+                nvr <- pkgNameVerRel' Rawhide (pkg <.> "spec")
+                promptEnter $ "Press Enter to push and build" +-+ nvr
+                gitPush True Nothing
+                -- FIXME build more branches
+                kojiBuildBranch "rawhide" (Package pkg) Nothing ["--fail-fast"]
+                putBugBuild False session bid nvr
+                existing <- fedoraBranchesNoRawhide (localBranches False)
+                when (null existing) $ do
+                  brs <- getRequestedBranches [] breq
+                  requestPkgBranches False False mock (Branches brs) (Package pkg)
+              srpmurls -> error' $ "multiple srpm urls:" +-+ unwords srpmurls
       when (pkg /= takeFileName dir) $
         setCurrentDirectory dir
+
       where
         findSRPMs :: Comment -> [T.Text]
         findSRPMs =
           filter (\ l -> "https://" `T.isInfixOf` l && any (`T.isPrefixOf` T.toLower l) ["srpm url:", "srpm:", "new srpm:", "updated srpm:"] && ".src.rpm" `T.isSuffixOf` l) . T.lines . commentText
+
+        maybeEncodeURI cs =
+          if '%' `elem` cs
+          then cs
+          else escapeURIString isUnescapedInURI cs
diff --git a/src/Cmd/Install.hs b/src/Cmd/Install.hs
--- a/src/Cmd/Install.hs
+++ b/src/Cmd/Install.hs
@@ -20,7 +20,6 @@
 import Repoquery
 import RpmBuild
 
--- FIXME --nobuild
 -- FIXME --rpm to avoid dnf
 -- FIXME --force removal of existing incompatible dependent packages
 -- FIXME --subpackage to specify subpackage(s) to install/add
@@ -29,8 +28,8 @@
 -- FIXME --check any/all of package installed
 -- FIXME add --debug or respect --verbose for dnf commands
 installCmd :: Bool -> Bool -> Maybe Branch -> Maybe ForceShort -> [BCond]
-           -> Bool -> Bool -> Bool -> (Maybe Branch,[String]) -> IO ()
-installCmd verbose recurse mfrom mforceshort bconds reinstall nobuilddeps allsubpkgs (mbr, pkgs) = do
+           -> Bool -> Bool -> Bool -> Bool -> (Maybe Branch,[String]) -> IO ()
+installCmd verbose recurse mfrom mforceshort bconds reinstall nobuild nobuilddeps allsubpkgs (mbr, pkgs) = do
   when (recurse && isShortCircuit mforceshort) $
     error' "cannot use --recurse and --shortcircuit"
   withPackagesMaybeBranch (boolHeader (recurse || length pkgs > 1)) True Nothing installPkg (mbr, pkgs)
@@ -59,7 +58,7 @@
       where
         doInstallPkg mforceshort' spec rpms already = do
           putStrLn $ (showNVR . dropArch . readNVRA) (head rpms)
-          unless nobuilddeps $ do
+          unless (nobuilddeps || nobuild) $ do
             missingdeps <- nub <$> (buildRequires spec >>= filterM notInstalled)
             unless (null missingdeps) $
               if recurse
@@ -71,11 +70,14 @@
                   mpkgdir <- lookForPkgDir rbr ".." dep
                   case mpkgdir of
                     Nothing -> putStrLn $ dep +-+ "not known"
-                    Just pkgdir -> installCmd verbose recurse mfrom mforceshort bconds reinstall nobuilddeps allsubpkgs (mbr, [pkgdir]) >> putNewLn
+                    Just pkgdir -> installCmd verbose recurse mfrom mforceshort bconds reinstall nobuild nobuilddeps allsubpkgs (mbr, [pkgdir]) >> putNewLn
                 -- FIXME option to enable/disable installing missing deps
                 -- FIXME --skip-missing-deps or prompt
               else installDeps True spec
-          wasbuilt <- buildRPMs (not verbose) False False mforceshort' bconds rpms br spec
+          wasbuilt <-
+            if nobuild
+            then return True
+            else buildRPMs (not verbose) False False mforceshort' bconds rpms br spec
           unless (isShortCircuit mforceshort') $ do
             toinstalls <-
               if allsubpkgs
diff --git a/src/Cmd/Local.hs b/src/Cmd/Local.hs
--- a/src/Cmd/Local.hs
+++ b/src/Cmd/Local.hs
@@ -112,7 +112,7 @@
       --    (refs/remotes/origin/HEAD has become dangling)
       -- Branch 'rawhide' set up to track remote branch 'rawhide' from 'origin'.
     -- compare commands with github rename
-    when ("rawhide" `notElem` locals) $ do
+    unless ("rawhide" `elem` locals) $ do
       git_ "fetch" ["--prune"]
       git_ "branch" ["--move", "master", "rawhide"]
       git_ "remote" ["set-head", "origin", "rawhide"]
diff --git a/src/Cmd/Parallel.hs b/src/Cmd/Parallel.hs
--- a/src/Cmd/Parallel.hs
+++ b/src/Cmd/Parallel.hs
@@ -28,7 +28,8 @@
 import RpmBuild (checkSourcesMatch, getDynSourcesMacros)
 import Types
 
-data JobDone = Done {jobNvr :: String,
+data JobDone = Done {_jobPkg :: Package,
+                     jobNvr :: String, -- maybe NVR?
                      jobBranch :: Branch,
                      _jobClog :: String}
 
@@ -44,10 +45,10 @@
 -- FIXME time builds
 -- FIXME copy bodhi notes from another branch update
 -- FIXME support non-sidetag update for parallel packages
-parallelBuildCmd :: Bool -> Maybe Bool -> Int -> Maybe SideTagTarget
+parallelBuildCmd :: Bool -> Maybe Bool -> Int -> Maybe SideTagTarget -> Double
                  -> (Maybe UpdateType, UpdateSeverity)
                  -> (BranchesReq, [String]) -> IO ()
-parallelBuildCmd dryrun mmerge firstlayer msidetagTarget mupdate (breq, pkgs) =
+parallelBuildCmd dryrun mmerge firstlayer msidetagTarget delay mupdate (breq, pkgs) =
   do
   branches <-
     case pkgs of
@@ -100,7 +101,7 @@
         when (length changelog > 10000) $
           putStrLn "Bodhi only accepts up to 10000 chars: will be truncated"
         -- FIXME allow editor
-        input <- prompt "Press Enter to use above or input update summary now; or 'no' to skip update"
+        input <- prompt "Press Enter to submit above or input Bodhi update summary now; or 'no' to skip update"
         unless (trim (lower input) `elem` ["no","n"] || dryrun) $
           bodhiSidetagUpdate rbr (map jobNvr nvrclogs) target $
           if null input then changelog else input
@@ -133,7 +134,7 @@
           target <- targetMaybeSidetag dryrun br msidetagTarget
           when (mmerge /= Just False) $ mergeNewerBranch Nothing br
           job <- startBuild Nothing 0 False (length brs) target pkg br "." >>= async
-          unless dryrun $ sleep 3
+          unless dryrun $ sleep delay
           return (show br,job)
 
     mergeNewerBranch :: Maybe Package -> Branch -> IO ()
@@ -160,7 +161,11 @@
         else ":"
       putStrLn $ unwords layer
       -- maybe print total pending packages
-      unless (null nextLayers) $
+      if null nextLayers
+        then
+        unless singlelayer $
+        putStrLn "no more layers"
+        else
         putStrLn $
         let layerspkgs = map length nextLayers
         in case layerspkgs of
@@ -196,7 +201,7 @@
           putPkgBrnchHdr pkg br
           job <- startBuild (if singlelayer then Nothing else Just layernum) n (layersleft > 0) nopkgs target pkg br dir
                  >>= async
-          unless dryrun $ sleep 4
+          unless dryrun $ sleep delay
           return (unPackage pkg,job)
 
     watchJobs :: Bool -> Maybe Int -> [String] -> [JobDone] -> [JobAsync]
@@ -258,7 +263,7 @@
           return $ do
             when morelayers $
               kojiWaitRepo dryrun (nopkgs > 5) True target nvr
-            return $ Done nvr br changelog
+            return $ Done pkg nvr br changelog
         Just BuildBuilding -> do
           putStrLn $ color Yellow nvr +-+ "is already" +-+ color Yellow "building"
           mtask <- kojiGetBuildTaskID fedoraHub nvr
@@ -267,7 +272,7 @@
             Just task ->
               return $ do
               kojiWaitTaskAndRepo (isNothing mlatest) nvr task
-              return $ Done nvr br changelog
+              return $ Done pkg nvr br changelog
         _ -> do
           when (null unpushed) $ do
             putStrLn $ nvr +-+ "(" ++ target ++ ")" +-+ show n +-+ "more" +-+
@@ -281,7 +286,7 @@
               putStrLn $ nvr +-+ "task is already open"
               return $ do
                 kojiWaitTaskAndRepo (isNothing mlatest) nvr task
-                return $ Done nvr br changelog
+                return $ Done pkg nvr br changelog
             (_:_) -> error' $ show (length opentasks) +-+ "open" +-+ unPackage pkg +-+ "tasks already"
             [] -> do
               if equivNVR nvr (fromMaybe "" mlatest)
@@ -292,12 +297,12 @@
                 else do
                 -- FIXME parse build output
                 if dryrun
-                  then return $ return $ Done nvr br "<changelog>"
+                  then return $ return $ Done pkg nvr br "<changelog>"
                   else do
                   task <- kojiBuildBranchNoWait target pkg Nothing $ "--fail-fast" : ["--background" | nopkgs > 5]
                   return $ do
                     kojiWaitTaskAndRepo (isNothing mlatest) nvr task
-                    return $ Done nvr br changelog
+                    return $ Done pkg nvr br changelog
       where
         kojiWaitTaskAndRepo :: Bool -> String -> TaskID -> IO ()
         kojiWaitTaskAndRepo newpkg nvr task = do
@@ -324,8 +329,8 @@
     -- FIXME map nvr to package?
     renderChangelogs :: [JobDone] -> [String]
     renderChangelogs [] = []
-    renderChangelogs ((Done nvr _ clog):jobs) =
-      unlines [nvr, "", clog] : renderChangelogs jobs
+    renderChangelogs ((Done pkg _ _ clog):jobs) =
+      unlines [unPackage pkg, "", clog] : renderChangelogs jobs
 
     -- FIXME how to catch authentication errors?
     bodhiSidetagUpdate :: Branch -> [String] -> String -> String -> IO ()
diff --git a/src/Cmd/PkgReview.hs b/src/Cmd/PkgReview.hs
--- a/src/Cmd/PkgReview.hs
+++ b/src/Cmd/PkgReview.hs
@@ -13,7 +13,7 @@
 
 import Data.Char
 import Network.HTTP.Directory (httpExists, httpManager)
-import SimplePrompt (promptEnter)
+import SimplePrompt (promptEnter, yesNoDefault)
 
 import Branches
 import Bugzilla
@@ -28,8 +28,8 @@
 -- FIXME add --dependent pkgreview
 -- FIXME verify tarball is same as upstream
 -- FIXME post URL field too
-createReview :: ScratchOption -> Bool -> [FilePath] -> IO ()
-createReview scratchOpt mock pkgs =
+createReview :: Maybe ScratchOption -> Bool -> [FilePath] -> IO ()
+createReview mscratchOpt mock pkgs =
   withPackagesByBranches HeaderMust False Nothing Zero createPkgReview (Branches [], pkgs)
   where
     createPkgReview :: Package -> AnyBranch -> IO ()
@@ -46,8 +46,8 @@
         -- FIXME abort if open review (unless --force?)
         promptEnter "Press Enter to continue"
       srpm <- generateSrpm Nothing spec
-      mockRpmLint mock (scratchOpt == ScratchBuild) pkg spec srpm
-      (mkojiurl,specSrpmUrls) <- buildAndUpload scratchOpt srpm pkg spec
+      mockRpmLint mock pkg spec srpm
+      (mkojiurl,specSrpmUrls) <- buildAndUpload mscratchOpt srpm pkg spec
       bugid <- postReviewReq session spec specSrpmUrls mkojiurl pkg
       putStrLn "Review request posted:"
       putBugId bugid
@@ -63,18 +63,28 @@
             , ("summary", "Review Request: " <> pkg <> " - " <> summary)
             , ("description", specSrpmUrls <> "\n\nDescription:\n" <> description <>  maybe "" ("\n\n\nKoji scratch build: " <>) mkojiurl)]
 
-buildAndUpload :: ScratchOption -> String -> String -> FilePath
+buildAndUpload :: Maybe ScratchOption -> String -> String -> FilePath
                -> IO (Maybe String, String)
-buildAndUpload scratchOpt srpm pkg spec = do
-  mkojiurl <- case scratchOpt of
-                ScratchBuild -> Just <$> kojiScratchBuild "rawhide" [] srpm
-                ScratchTask tid -> return $ Just ("https://koji.fedoraproject.org/koji/taskinfo?taskID=" ++ show tid)
-                SkipScratch -> return Nothing
+buildAndUpload mscratchOpt srpm pkg spec = do
+  scratch <-
+    if isNothing mscratchOpt
+    then yesNoDefault False "Would you like to do a koji scratch build"
+    else do
+      return $ mscratchOpt == Just ScratchBuild
+  promptEnter $ "Press Enter to" +-+ if scratch
+                                     then "submit"
+                                     else "upload"
+  mkojiurl <- case mscratchOpt of
+                Just (ScratchTask tid) -> return $ Just ("https://koji.fedoraproject.org/koji/taskinfo?taskID=" ++ show tid)
+                _ ->
+                  if scratch
+                  then Just <$> kojiScratchBuild "rawhide" [] srpm
+                  else return Nothing
   specSrpmUrls <- uploadPkgFiles pkg spec srpm
   return (mkojiurl, specSrpmUrls)
 
-updateReview :: ScratchOption -> Bool -> Maybe FilePath -> IO ()
-updateReview scratchOpt mock mspec = do
+updateReview :: Maybe ScratchOption -> Bool -> Maybe FilePath -> IO ()
+updateReview mscratchOpt mock mspec = do
   spec <- maybe findSpecfile checkLocalFile mspec
   pkg <- cmd "rpmspec" ["-q", "--srpm", "--qf", "%{name}", spec]
   (bid,session) <- reviewBugIdSession pkg
@@ -83,8 +93,8 @@
   submitted <- checkForComment session bid (T.pack srpm)
   when submitted $
     error' "This NVR was already posted on the review bug: please bump"
-  mockRpmLint mock (scratchOpt == ScratchBuild) pkg spec srpm
-  (mkojiurl,specSrpmUrls) <- buildAndUpload scratchOpt srpm pkg spec
+  mockRpmLint mock pkg spec srpm
+  (mkojiurl,specSrpmUrls) <- buildAndUpload mscratchOpt srpm pkg spec
   changelog <- changeLogPrompt False spec
   commentBug session bid (specSrpmUrls <> (if null changelog then "" else "\n\n" <> changelog) <> maybe "" ("\n\nKoji scratch build: " <>) mkojiurl)
   -- putStrLn "Review bug updated"
@@ -117,8 +127,8 @@
           okay <- httpExists mgr url
           unless okay $ error' $ "Could not access:" +-+ url
 
-mockRpmLint :: Bool -> Bool -> String -> FilePath -> FilePath -> IO ()
-mockRpmLint mock scratch pkg spec srpm = do
+mockRpmLint :: Bool -> String -> FilePath -> FilePath -> IO ()
+mockRpmLint mock pkg spec srpm = do
   rpms <-
     if mock then do
       -- FIXME check that mock is installed
@@ -129,7 +139,6 @@
       builtRpms (RelBranch Rawhide) spec >>= filterM doesFileExist
   -- FIXME parse # of errors/warnings
   void $ cmdBool "rpmlint" $ spec:srpm:rpms
-  promptEnter $ "Press Enter to" +-+ if scratch then "submit" else "upload"
 
 -- FIXME does not work with pkg dir/spec:
 -- 'fbrnch: No spec file found'
diff --git a/src/Cmd/Prep.hs b/src/Cmd/Prep.hs
--- a/src/Cmd/Prep.hs
+++ b/src/Cmd/Prep.hs
@@ -15,8 +15,9 @@
 data PrepPre = PrepClone | PrepPull
   deriving Eq
 
-prepCmd :: Maybe PrepPre -> Bool -> (Maybe Branch,[String]) -> IO ()
-prepCmd mpre verbose (mbr,pkgs) = do
+-- FIXME prompt for cloning
+prepCmd :: Maybe PrepPre -> Bool -> Bool -> (Maybe Branch,[String]) -> IO ()
+prepCmd mpre verbose deps (mbr,pkgs) = do
   when (mpre == Just PrepClone) $
     cloneCmd (ClonePkgs (mbr, pkgs))
   withPackagesMaybeBranchNoHeadergit prepPackage (mbr,pkgs)
@@ -36,6 +37,8 @@
         unlessM (doesFileExist spec) $
           error' $ spec +-+ "not found"
         getSourcesMacros spec
+        when deps $
+          installDeps False spec
         case br of
           RelBranch rbr -> do
             nvr <- pkgNameVerRel' rbr spec
@@ -43,5 +46,5 @@
             putStr $ "Prepping" +-+ nvr ++ ": "
           _ -> return ()
         timeIO $
-          (if verbose then cmdLog else cmdSilent') "rpmbuild" ["-bp", "--nodeps", spec]
+          (if verbose then cmdLog else cmdSilent') "rpmbuild" $ "-bp" : ["--nodeps" | not deps] ++ [spec]
         putStrLn "done"
diff --git a/src/Cmd/RequestRepo.hs b/src/Cmd/RequestRepo.hs
--- a/src/Cmd/RequestRepo.hs
+++ b/src/Cmd/RequestRepo.hs
@@ -55,15 +55,13 @@
         putNewLn
         promptEnter "Press Enter to continue"
         -- FIXME check api key is still valid or open pagure ticket directly
-        url <- fedpkg "request-repo" [pkg, show bid]
-        let assignee = userRealName (bugAssignedToDetail bug)
-        let draft = "Thank you for the review" ++ maybe "" ("," +-+) (getFirstname assignee)
+        fedpkg_ "request-repo" [pkg, show bid]
+        let draft = "Thank you for the review" ++ maybe "" ("," +-+) (assigneeFirstname $ bugAssignedToDetail bug)
         putStrLn "```"
         putStrLn draft
         putStrLn "```"
-        putStrLn $ url ++ "\n"
         input <- promptInitial "Enter comment" draft
-        let comment = (if null input then draft else input) ++ "\n\n" <> url
+        let comment = (if null input then draft else input)
         commentBug session bid comment
         putNewLn
         branches <- getRequestedBranches [] breq
@@ -95,9 +93,11 @@
         error' $ "Repo for" +-+ pkg +-+ "already exists"
 
     -- FIXME handle "email name"
-    getFirstname :: T.Text -> Maybe String
-    getFirstname t =
-      let first = head (T.words t) in
-        if "@" `T.isInfixOf` first
-        then Nothing
-        else Just (T.unpack first)
+    assigneeFirstname :: User -> Maybe String
+    assigneeFirstname assignee =
+      case T.words $ userRealName assignee of
+          [] -> Nothing
+          first:_ ->
+            if "@" `T.isInfixOf` first
+            then Nothing
+            else Just (T.unpack first)
diff --git a/src/Cmd/Scratch.hs b/src/Cmd/Scratch.hs
--- a/src/Cmd/Scratch.hs
+++ b/src/Cmd/Scratch.hs
@@ -59,7 +59,13 @@
                 ExcludedArchs as -> do
                   Just (buildtag,_desttag) <- kojiBuildTarget fedoraHub target
                   tagArchs <- kojiTagArchs buildtag
-                  return $ tagArchs \\ as
+                  excludedarchs <- do
+                    excluded <- map words . filter ("ExcludeArch:" `isPrefixOf`) <$> cmdLines "rpmspec" ["-P", spec]
+                    return $
+                      if null excluded
+                      then return []
+                      else concatMap tail excluded
+                  return $ tagArchs \\ (as ++ excludedarchs)
         if stagger
           then do
           archlist <-
diff --git a/src/Cmd/Status.hs b/src/Cmd/Status.hs
--- a/src/Cmd/Status.hs
+++ b/src/Cmd/Status.hs
@@ -135,8 +135,8 @@
 #endif
 
 
-unpushedCmd :: Bool -> (BranchesReq,[String]) -> IO ()
-unpushedCmd latest (breq, pkgs) =
+unpushedCmd :: Bool -> Bool -> (BranchesReq,[String]) -> IO ()
+unpushedCmd latest bump (breq, pkgs) =
   -- FIXME dirty not okay for multiple branches?
   withPackagesByBranches (if latest then HeaderMay else HeaderMust) False dirtyGit AnyNumber unpushedBranch (breq, pkgs)
   where
@@ -155,24 +155,44 @@
         let spec = packageSpec pkg
             prefix =
               let pref =
-                    (if length pkgs > 1 then unPackage pkg else "") +-+
+                    (if length pkgs > 1 && latest
+                     then unPackage pkg else "") +-+
                     case breq of
                       Branches brs | length brs <= 1 -> ""
                       _ -> show br
               in if null pref then "" else pref ++ ":"
-        ifM (notM (doesFileExist spec))
-          (ifM initialPkgRepo
-            (putStrLn $ prefix +-+ "initial repo")
-            (unlessM (doesFileExist "dead.package") $
-             putStrLn $ "missing" +-+ spec)) $
-          do
+        haveSpec <- doesFileExist spec
+        if not haveSpec
+          then
+          ifM initialPkgRepo
+          (putStrLn $ prefix +-+ "initial repo") $
+          ifM (doesFileExist "dead.package")
+          (putStrLn $ prefix +-+ "dead package") $
+          putStrLn $ prefix +-+ "missing" +-+ spec
+          else do
           whenM (isNothing <$> pkgNameVerRel br spec) $ do
             putStrLn "undefined NVR!\n"
             putStr "HEAD "
           unpushed <- gitShortLogN (if latest then Just 1 else Nothing) $
                       Just $ "origin/" ++ show br ++ "..HEAD"
-          if latest
+          if null unpushed
+            then
+            when bump $ doBump spec
+            else
+            if latest
             then whenJust (listToMaybe unpushed) $ putCommit prefix
             else mapM_ (putCommit prefix) unpushed
 
     putCommit prefix = putStrLn . (prefix +-+) . showCommit
+
+    doBump spec = do
+      checkWorkingDirClean
+      dead <- doesFileExist "dead.package"
+      if dead
+        then putStrLn "dead package"
+        else do
+        putStrLn "bumping"
+        autorelease <- isAutoRelease spec
+        unless autorelease $
+          cmd_ "rpmdev-bumpspec" ["-c", "rebuild", spec]
+        git_ "commit" $ "-a" : (if autorelease then ("--allow-empty" :) else id) ["-m", "bump release"]
diff --git a/src/Cmd/Update.hs b/src/Cmd/Update.hs
--- a/src/Cmd/Update.hs
+++ b/src/Cmd/Update.hs
@@ -39,11 +39,11 @@
         in if pkgGit
            then dirty
            else if null pkgs then Nothing else dirty
-  withPackagesMaybeBranch HeaderMay False mgitops (updatePkg mver) (mbr, pkgs)
+  withPackagesMaybeBranch HeaderMay False mgitops (updatePkg pkgGit mver) (mbr, pkgs)
   where
-    updatePkg :: Maybe String -> Package -> AnyBranch -> IO ()
-    updatePkg mver pkg br = do
-      when (br /= RelBranch Rawhide) $
+    updatePkg :: Bool -> Maybe String -> Package -> AnyBranch -> IO ()
+    updatePkg distgit mver pkg br = do
+      when (distgit && br /= RelBranch Rawhide) $
         promptEnter $ "Are you sure you want to update" +-+ show br +-+ "branch?!"
       spec <- if allowHEAD
               then findSpecfile
@@ -108,7 +108,7 @@
           cmd_ "rpmdev-bumpspec" ["-c", "update to" +-+ newver, spec]
           git_ "commit" ["-a", "-m", "update to" +-+ newver]
       putStr "Prepping... "
-      cmdSilent' "rpmbuild" ["-bp", spec]
+      cmdSilent' "rpmbuild" ["-bp", "--nodeps", spec]
       putStrLn "done"
       -- FIXME git amend (if previous commit was update)
 
@@ -122,7 +122,10 @@
     -- FIXME handle .tgz?
     isArchiveFile :: FilePath -> Bool
     isArchiveFile f =
-      ".tar." `isInfixOf` f || ".zip" `isSuffixOf` f
+      any ($ f) [(".tar." `isInfixOf`),
+                 (".zip" `isSuffixOf`),
+                 (".gpg" `isSuffixOf`),
+                 (".tgz" `isSuffixOf`)]
 
 pkgVerRel :: FilePath -> IO (String,String)
 pkgVerRel spec = do
diff --git a/src/Common.hs b/src/Common.hs
--- a/src/Common.hs
+++ b/src/Common.hs
@@ -11,12 +11,14 @@
   (+-+),
   plural,
   pluralException,
-  putNewLn
+  putNewLn,
+  reverseSort
   ) where
 
 import Control.Monad.Extra -- hiding (loop)
 import Data.List.Extra hiding (list, merge)
 import Data.Maybe
+import Data.Ord (comparing, Down(Down))
 
 #if !MIN_VERSION_base(4,11,0)
 import Data.Semigroup ((<>))
@@ -40,3 +42,6 @@
 
 putNewLn :: IO ()
 putNewLn = putChar '\n'
+
+reverseSort :: Ord a => [a] -> [a]
+reverseSort = sortBy (comparing Down)
diff --git a/src/Git.hs b/src/Git.hs
--- a/src/Git.hs
+++ b/src/Git.hs
@@ -186,7 +186,7 @@
                    if "From " `isPrefixOf` hd then tl else hd:tl
   if null filtered
     then unless quiet $ putStrLn "done"
-    else putStrLn $ intercalate "\n" filtered
+    else putStrLn $ '\r' : intercalate "\n" filtered
 
 checkWorkingDirClean :: IO ()
 checkWorkingDirClean = do
@@ -301,7 +301,7 @@
     (c:cs) -> do
       -- FIXME use promptMap
       ref <- prompt txt
-      case lower (trim ref) of
+      case lower ref of
         "" -> return $ Just c
         "y" -> return $ Just c
         "yes" -> return $ Just c
diff --git a/src/Koji.hs b/src/Koji.hs
--- a/src/Koji.hs
+++ b/src/Koji.hs
@@ -111,7 +111,7 @@
   -- for git: drop "Created task: "
   -- init to drop final newline
   unless (B.null out) $
-    logMsg $ (B.unpack . B.init . B.unlines . tail . B.lines) out
+    logMsg $ (dropPrefix "Task info: " . B.unpack . B.init . B.unlines . tail . B.lines) out
   if ret == ExitSuccess
     then do
     let kojiurl = B.unpack $ last $ B.words out
@@ -143,10 +143,9 @@
   case mst of
     Just TaskClosed -> return ()
     Just TaskFailed -> do
-      let kojitool = "/usr/bin/koji-tool"
-      whenM (doesFileExist kojitool) $
-        -- FIXME fails to output when run immediately? (cmdlog deprecated)
-        cmdlog kojitool ["tasks", displayID task, "--tail", "-s", "fail"]
+      whenJustM (findExecutable "koji-tool") $ \kojitool ->
+        -- FIXME cmdLog deprecated
+        cmdLog kojitool ["tasks", displayID task, "--tail", "-s", "fail"]
       error' "Task failed!"
     Just TaskCanceled -> return ()
     _ -> kojiWatchTask task
diff --git a/src/Krb.hs b/src/Krb.hs
--- a/src/Krb.hs
+++ b/src/Krb.hs
@@ -16,8 +16,12 @@
     else
     when (last krb == "(Expired)") $ do
       putStrLn $ unwords krb
-      cmd_ "fkinit" []
+      fkinit
       putNewLn
+  where
+    fkinit = do
+      ok <- cmdBool "fkinit" []
+      unless ok fkinit
 
 maybeFasIdFromKrb :: IO (Maybe String)
 maybeFasIdFromKrb =
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -77,7 +77,7 @@
       <*> branchesPackages
     , Subcommand "merge" "Merge from newer branch" $
       mergeCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run (do not merge)"
       <*> switchLongWith "no-fetch" "Skip git fetch"
       <*> nopromptOpt
       <*> optional (optionWith auto 's' "skip-bumps" "NUM" "Max num of rebuild commits to ignore [default 0]")
@@ -87,6 +87,7 @@
     , Subcommand "unpushed" "Show unpushed commits" $
       unpushedCmd
       <$> switchWith 'l' "latest" "Only show latest unpushed commit"
+      <*> switchWith 'b' "bump" "Bump release (and commit) if no local commits"
       <*> branchesPackages
     , Subcommand "build" "Build package(s) in Koji" $
       buildCmd
@@ -109,10 +110,11 @@
       <*> branchesPackages
     , Subcommand "parallel" "Parallel build packages in Koji" $
       parallelBuildCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not build anything"
       <*> mergeOpt
       <*> optionalWith auto 'l' "skip-to-layer" "LAYERNO" "Skip the first N layers [default 0]" 0
       <*> optional (sidetagTargetOpt $ Just "or creates one for you (with 'fedpkg request-side-tag --base-tag')")
+      <*> optionalWith auto 'd' "delay" "SECONDS" "Sleep delay between starting builds [default 4.0]" 4
       <*> updateOpt
       <*> branchesPackages
     , Subcommand "sidetags" "List user's side-tags" $
@@ -121,21 +123,21 @@
       <*> many branchArg
     , Subcommand "override" "Tag builds into buildroot override in Koji" $
       overrideCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not override"
       <*> overrideModeOpt
       <*> optional (optionWith auto 'd' "duration" "DAYS" "Number of days until expiry [default 4]")
       <*> switchWith 'w' "no-wait" "Skip waitrepo step"
       <*> branchesPackages
     , Subcommand "waitrepo" "Wait for build to appear in Koji buildroot" $
       waitrepoCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not wait"
       <*> pure False
       <*> waitfetchOpt
       <*> optional (sidetagTargetOpt Nothing)
       <*> branchesPackages
     , Subcommand "scratch" "Scratch build package in Koji" $
       scratchCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not build"
       <*> switchLongWith "stagger" "Stagger archs"
       <*> rebuildSrpmOpt
       <*> noFailFastOpt
@@ -145,7 +147,7 @@
       <*> branchesPackages
     , Subcommand "scratch-aarch64" "Koji aarch64 scratch build of package" $
       scratchCmdAarch64
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not build"
       <*> rebuildSrpmOpt
       <*> switchWith 'X' "exclude-arch" "Exclude aarch64"
       <*> many (sidetagTargetOpt Nothing)
@@ -153,12 +155,17 @@
       <*> branchesPackages
     , Subcommand "scratch-x86_64" "Koji x86_64 scratch build of package" $
       scratchCmdX86_64
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not build"
       <*> rebuildSrpmOpt
       <*> switchWith 'X' "exclude-arch" "Exclude x86_64"
       <*> many (sidetagTargetOpt Nothing)
       <*> optional scratchSourceOpt
       <*> branchesPackages
+    , Subcommand "update-sources" "Download and update newer sources" $
+      updateCmd True
+      <$> switchWith 'f' "force" "Download upstream sources even if they exist locally"
+      <*> switchWith 'H' "allow-head" "For updating inside rebase"
+      <*> maybeBranchPackages False
     , Subcommand "update-version" "Update package in dist-git to newer version" $
       updateCmd
       <$> switchWith 's' "sources-only" "Only update sources"
@@ -174,6 +181,7 @@
       prepCmd
       <$> optional prepPreOpts
       <*> switchWith 'v' "verbose" "show rpmbuild output"
+      <*> switchWith 'd' "deps" "require deps to be installed"
       <*> maybeBranchPackages False
     , Subcommand "local" "Build locally" $
       localCmd
@@ -214,7 +222,7 @@
       <*> branchPackages
     , Subcommand "mock" "Local mock build" $
       mockCmd
-      <$> switchWith 'n' "dry-run" "Do not build (but creates srpm)"
+      <$> dryrunOpt "Do not build (but creates srpm)"
       <*> optional nocleanOpt
       <*> switchWith 'N' "network" "Use network during build"
       <*> optional (flagLongWith' ShellOnly "shell-only" "Skip mock build" <|>
@@ -234,7 +242,8 @@
       <*> optional forceshortOpt
       <*> many bcondOpt
       <*> switchWith 'r' "reinstall" "reinstall rpms"
-      <*> switchWith 'B' "ignore-builddeps" "do not install builddeps"
+      <*> switchLongWith "no-build" "do not (re-)build (install built rpms)"
+      <*> switchLongWith "ignore-builddeps" "do not install builddeps"
       <*> switchWith 'a' "all-subpackages" "install all subpackages (default if none currently installed)"
       <*> maybeBranchPackages False
     , Subcommand "not-installed" "Packages not installed locally" $
@@ -246,7 +255,8 @@
       <*> manyPackages
     , Subcommand "bump" "Bump release for package" $
       bumpPkgs
-      <$> switchWith 'l' "local" "Use local origin rather than checking latest koji"
+      <$> dryrunOpt "Dry run: do not bump"
+      <*> switchWith 'l' "local" "Use local origin rather than checking latest koji"
       <*> optional commitOpts
       <*> optional (strOptionWith 'c' "changelog" "CLOGENTRY"
                     "Override changelog entry [default: rebuild]")
@@ -266,7 +276,7 @@
       <$> manyPackages
     , Subcommand "push" "Git push packages" $
       pushPkgs
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not push"
       <*> switchLongWith "no-fetch" "Skip git fetch"
       <*> optional (strOptionWith 'r' "ref" "COMMITHASH" "git commit to push")
       <*> branchesPackages
@@ -278,12 +288,12 @@
       <$> strArg "NAME"
     , Subcommand "create-review" "Create a Package Review request" $
       createReview
-      <$> scratchOpt
+      <$> optional scratchOpt
       <*> mockOpt False
       <*> manyPackages
     , Subcommand "update-review" "Update a Package Review" $
       updateReview
-      <$> scratchOpt
+      <$> optional scratchOpt
       <*> mockOpt False
       <*> optional (strArg "SPECFILE")
     , Subcommand "review-package" "Run fedora-review on a package Review Request bug" $
@@ -327,7 +337,7 @@
       <*> branchesPackages
     , Subcommand "copr" "Build package(s) in Fedora Copr" $
       coprCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "Dry run: do not build"
       <*> switchWith 'l' "list-chroots" "Show project chroots"
       <*> buildByOpt
       <*> optional archesOpt
@@ -348,7 +358,7 @@
     --   <$> branchesPackages
     , Subcommand "ftbfs" "Check FTBFS status" $
       ftbfsCmd
-      <$> dryrunOpt
+      <$> dryrunOpt "dry run"
       <*> switchWith 'l' "short" "Only list packages"
       <*> optional (flagWith' (FtbfsUser Nothing) 'M' "mine" "Your packages"
                     <|>
@@ -495,7 +505,7 @@
       <*> optional (sidetagTargetOpt Nothing)
       <*> overrideOpt
       <*> waitrepoOpt
-      <*> dryrunOpt
+      <*> dryrunOpt "Dry run: do not merge/push/build"
       <*> skipFetchOpt
       <*> updateOpt
       <*> useChangelogOpt
@@ -523,7 +533,8 @@
     archesOpt :: Parser Archs
     archesOpt = Archs <$> some archOpt <|> ExcludedArchs <$> some excludeArch
 
-    dryrunOpt = switchWith 'n' "dry-run" "Do not write (push, build, post, override)"
+    -- FIXME allow "dryrun"
+    dryrunOpt = switchWith 'n' "dry-run"
 
     skipFetchOpt = switchWith 'S' "skip-fetch" "Do not git fetch"
 
@@ -610,8 +621,9 @@
 
     scratchOpt :: Parser ScratchOption
     scratchOpt =
-      ScratchTask <$> optionWith auto 's' "scratch-build" "TASKID" "Existing scratch build taskid" <|>
-      flagWith ScratchBuild SkipScratch 'S' "no-scratch" "Skip scratch build"
+      ScratchTask <$> optionLongWith auto "scratch-task" "TASKID" "Existing scratch build taskid" <|>
+      flagWith' SkipScratch 'S' "no-scratch" "Skip koji scratch build" <|>
+      flagWith' ScratchBuild 's' "scratch" "Do koji scratch build without prompt"
 
     scratchSourceOpt :: Parser ScratchSource
     scratchSourceOpt =
diff --git a/src/Package.hs b/src/Package.hs
--- a/src/Package.hs
+++ b/src/Package.hs
@@ -362,11 +362,10 @@
     if autorelease
     then do
       --putStrLn "%autorelease detected"
-      mautospec <- findExecutable "rpmautospec"
-      when (isNothing mautospec) $
-        error' "requires rpmautospec.."
-      autorel <- last . words <$> cmd "rpmautospec" ["calculate-release", spec]
-      rpmspec ["--srpm"] (Just ("%{name}-%{version}-" ++ autorel ++ disttag)) spec
+      mfedpkg <- findExecutable "fedpkg"
+      when (isNothing mfedpkg) $
+        error' "requires fedpkg.."
+      cmdLines "fedpkg" ["verrel"]
     else rpmspec ["--srpm"] (Just "%{name}-%{version}-%{release}") spec
   seq disttag $
     return $
diff --git a/src/RpmBuild.hs b/src/RpmBuild.hs
--- a/src/RpmBuild.hs
+++ b/src/RpmBuild.hs
@@ -17,6 +17,7 @@
   )
 where
 
+import Control.Exception (uninterruptibleMask_)
 import Data.Char (isDigit)
 import Data.Either (partitionEithers)
 import Data.RPM
@@ -185,7 +186,9 @@
         return srpmfile
   where
     buildSrpm opts = do
-      srpm <- last . words <$> cmd "rpmbuild" (opts ++ ["-bs", spec])
+      -- prevent Ctrl-c from truncating srpm to corrupted file:
+      -- 'Error: Downloaded rpm http://kojipkgs-cache01.s390.fedoraproject.org/work/cli-build/1691493908.5614614.AzJmareV/ghc9.4-9.4.6-22.fc39.src.rpm is corrupted:'
+      srpm <- last . words <$> uninterruptibleMask_ (cmd "rpmbuild" (opts ++ ["-bs", spec]))
       putStrLn $ "Created" +-+ takeFileName srpm
       return srpm
 
