[#135] Improve stash command (#186)

* [#135] Improve `stash` command

Resolves #135

* Update changelog
This commit is contained in:
Dmitrii Kovanikov 2020-07-04 11:42:19 +01:00 committed by GitHub
parent a91ce7b736
commit 7082774b7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 43 deletions

View File

@ -57,6 +57,13 @@ The changelog is available [on GitHub][2].
Add labels from the issue in the `hit pr` command.
* [#165](https://github.com/kowainik/hit-on/issues/165):
Add `hit fork` command.
* [#159](https://github.com/kowainik/hit-on/issues/159):
Add `hit wip` command.
* [#136](https://github.com/kowainik/hit-on/issues/136):
Add `--force` flag to the `hit sync` command.
* [#135](https://github.com/kowainik/hit-on/issues/135):
Implement `hit stash diff`, `hit stash list`, `hit stash clear` commands.
Add `--name` option to `hit stash` for named stashes.
### 0.1.0.0 — Aug 3, 2019

View File

@ -84,7 +84,6 @@ library
Hit.Git.Status
Hit.Git.Sync
Hit.Git.Uncommit
Hit.Git.Unstash
Hit.Git.Wip
Hit.GitHub
Hit.Hub

View File

@ -21,13 +21,15 @@ import Data.Version (showVersion)
import Development.GitRev (gitCommitDate, gitHash)
import Options.Applicative (CommandFields, Mod, Parser, ParserInfo, argument, auto, command,
execParser, flag, flag', fullDesc, help, helper, info, infoOption, long,
metavar, option, progDesc, short, strArgument, subparser, switch)
metavar, option, progDesc, short, strArgument, strOption, subparser,
switch)
import Hit.Core (CommitOptions (..), ForceFlag (..), IssueOptions (..), Milestone (..),
NewOptions (..), defaultIssueOptions)
import Hit.Git (runAmend, runClear, runClone, runCommit, runCurrent, runDiff, runFix, runFork,
runFresh, runHop, runLog, runMilestones, runNew, runPr, runPush, runRename,
runResolve, runStash, runStatus, runSync, runUncommit, runUnstash, runWip)
runResolve, runStatus, runSync, runUncommit, runWip)
import Hit.Git.Stash (runStash, runStashClear, runStashDiff, runStashList, runUnstash)
import Hit.Issue (runIssue)
import Hit.Prompt (arrow)
@ -42,7 +44,11 @@ hit = execParser cliParser >>= \case
New newOptions -> runNew newOptions
Rename issueNumOrBranch -> runRename issueNumOrBranch
Issue issueOpts -> runIssue issueOpts
Stash -> runStash
Stash cmd -> case cmd of
StashSave name -> runStash name
StashDiff num -> runStashDiff num
StashClear forceFlag -> runStashClear forceFlag
StashList -> runStashList
Unstash -> runUnstash
Commit opts -> runCommit opts
Wip -> runWip
@ -78,7 +84,7 @@ data HitCommand
| New !NewOptions
| Rename !Text -- ^ Issue number or branch name
| Issue IssueOptions
| Stash
| Stash !StashCmd
| Unstash
| Commit CommitOptions
| Wip
@ -102,6 +108,23 @@ data HitCommand
| Pr
!Bool -- ^ Create a draft PR?
-- | Subcommands for the @git stash@ command
data StashCmd
-- | @git stash@ or @git stash push@ if name is provided
= StashSave
!(Maybe Text) -- ^ Optional name
-- | @git stash show@ - show diff
| StashDiff
!(Maybe Int) -- ^ Stash index
-- | @git stash list@
| StashList
-- | @git stash clear@
| StashClear
!ForceFlag
-- | Commands parser.
hitP :: Parser HitCommand
hitP = subparser
@ -163,7 +186,30 @@ issueP = do
pure $ Issue IssueOptions {..}
stashP :: Parser HitCommand
stashP = pure Stash
stashP = Stash <$> stashCmdP
where
stashCmdP :: Parser StashCmd
stashCmdP = stashListP <|> stashDiffP <|> stashClearP <|> stashSaveP
stashListP, stashDiffP, stashClearP:: Parser StashCmd
stashListP = subcom "list" (pure StashList) "List all stashes"
stashClearP = subcom "clear" (StashClear <$> forceFlagP) "Clear all stashes"
stashDiffP = subcom "diff" (StashDiff <$> stashIndexP) "Show diff with the given stash"
where
stashIndexP :: Parser (Maybe Int)
stashIndexP = optional $ argument auto $ help "Index of stash"
stashSaveP :: Parser StashCmd
stashSaveP = do
stashName <- optional $ strOption $ mconcat
[ long "name"
, metavar "STRING"
, help "Name of stash"
]
pure $ StashSave stashName
subcom :: String -> Parser StashCmd -> String -> Parser StashCmd
subcom name p desc = subparser $ command name (info p $ progDesc desc)
unstashP :: Parser HitCommand
unstashP = pure Unstash

View File

@ -53,9 +53,8 @@ import Hit.Git.Milestones (runMilestones)
import Hit.Git.Pr (runPr)
import Hit.Git.Push (runPush)
import Hit.Git.Resolve (runResolve)
import Hit.Git.Stash (runStash)
import Hit.Git.Stash (runStash, runUnstash)
import Hit.Git.Status (runStatus)
import Hit.Git.Sync (runSync)
import Hit.Git.Uncommit (runUncommit)
import Hit.Git.Unstash (runUnstash)
import Hit.Git.Wip (runWip)

View File

@ -11,6 +11,7 @@ Portability : Portable
module Hit.Git.Clear
( runClear
, clearWithPrompt
) where
import Colourista (infoMessage)
@ -22,19 +23,27 @@ import Hit.Prompt (Answer (..), prompt, yesOrNoText)
-- | Remove all local changes permanently.
runClear :: ForceFlag -> IO ()
runClear = \case
Force -> clearChanges
Simple -> do
putText $ unlines
[ "This command permanently deletes all uncommited changes"
, "Hint: if you want to save changes, use 'hit stash' command."
, "Are you sure you want to delete changes? " <> yesOrNoText N
]
prompt N >>= \case
N -> infoMessage "Aborting local clean up"
Y -> clearChanges
runClear = clearWithPrompt clearChanges
[ "This command permanently deletes all uncommited changes"
, "Hint: if you want to save changes, use 'hit stash' command."
, "Are you sure you want to delete changes? " <> yesOrNoText N
]
where
clearChanges :: IO ()
clearChanges = do
"git" ["add", "."]
"git" ["reset", "--hard"]
-- | Clear guarded by 'ForceFlag'
clearWithPrompt
:: IO () -- ^ Clearing action
-> [Text] -- ^ Long description
-> ForceFlag
-> IO ()
clearWithPrompt clear desc = \case
Force -> clear
Simple -> do
putText $ unlines desc
prompt N >>= \case
N -> infoMessage "Aborting clearing action"
Y -> clear

View File

@ -6,16 +6,51 @@ Maintainer : Kowainik <xrom.xkov@gmail.com>
Stability : Stable
Portability : Portable
@hit stash@ command runner and helpers.
Family of @hit stash@ and @hit unstash@ commands runners and helpers.
-}
module Hit.Git.Stash
( runStash
, runStashClear
, runStashDiff
, runStashList
, runUnstash
) where
import Shellmet ()
import Hit.Core (ForceFlag (..))
import Hit.Git.Clear (clearWithPrompt)
import Hit.Prompt (Answer (..), yesOrNoText)
-- | @hit stash@ command: save all local changes to stash.
runStash :: IO ()
runStash = "git" ["stash", "--include-untracked"]
runStash :: Maybe Text -> IO ()
runStash mName = do
let args = case mName of
Nothing -> ["--include-untracked"]
Just name -> ["push", "--include-untracked", "-m", name]
"git" $ "stash" : args
-- | @hit stash clear@ command: clear all stashes.
runStashClear :: ForceFlag -> IO ()
runStashClear = clearWithPrompt clearCmd
[ "This command permanently deletes all stashed changes"
, "Are you sure you want to delete changes? " <> yesOrNoText N
]
where
clearCmd :: IO ()
clearCmd = "git" ["stash", "list"]
-- | @hit stash diff@ command: show diff with the given stash.
runStashDiff :: Maybe Int -> IO ()
runStashDiff (fromMaybe 0 -> num) =
"git" ["stash", "show", "-p", "stash@{" <> show num <> "}"]
-- | @hit stash list@ command: list all stashes.
runStashList :: IO ()
runStashList = "git" ["stash", "list"]
-- | @hit unstash@ command: pop all saved changes.
runUnstash :: IO ()
runUnstash = "git" ["stash", "pop"]

View File

@ -1,21 +0,0 @@
{- |
Module : Hit.Git.Unstash
Copyright : (c) 2019-2020 Kowainik
SPDX-License-Identifier : MPL-2.0
Maintainer : Kowainik <xrom.xkov@gmail.com>
Stability : Stable
Portability : Portable
@hit unstash@ command runner and helpers.
-}
module Hit.Git.Unstash
( runUnstash
) where
import Shellmet ()
-- | @hit unstash@ command: pop all saved changes.
runUnstash :: IO ()
runUnstash = "git" ["stash", "pop"]