This is the companion of "git switch" and is based on that topic.
This command peforms the "checkout paths" from git-checkout, git-reset
and also has a third mode to reset only worktree, leaving the index
alone.

For new people not aware of previous discussions, this command is
supposed to be a friendlier replacement for "git checkout" and
hopefully fixes some warts that have grown over the time in
git-checkout. For this reason, the last patch starts to recommend "git
restore" everywhere.

v2 should address all the comments from v1. I still haven't done that
--intent-to-add thing yet even though I'd like to make it default
behavior too. Anyway changes are

- --index is renamed to --staged to avoid conflict with --index from
  git-apply, which has different meaning.

- lots of document fixes. The comparison between restore/revert/reset
  is added in git.txt instead. I want to avoid duplicate the same
  thing on three man pages.

- --force is dropped. --ignore-unmerged takes its place.

- --recurse-submodules is dropped. I've concluded that restoring files
  across submodule boundary is not exactly supported yet. Let's leave it
  for later.

- git-rm learns about --staged as an alias of --cached (in fact it's
  more the other way around). This is to keep suggestions consistent
  because we tell people to do "git foo --staged" everywhere.

- git-reset and git-diff are moved to other groups in "git help"
  output.

Nguyễn Thái Ngọc Duy (16):
  checkout: split part of it to new command 'restore'
  restore: take tree-ish from --source option instead
  restore: make pathspec mandatory
  restore: disable overlay mode by default
  checkout: factor out worktree checkout code
  restore: add --worktree and --staged
  restore: reject invalid combinations with --staged
  restore: default to --source=HEAD when only --staged is specified
  restore: replace --force with --ignore-unmerged
  restore: support --patch
  t: add tests for restore
  completion: support restore
  user-manual.txt: prefer 'merge --abort' over 'reset --hard'
  doc: promote "git restore"
  rm: add --staged as alias for --cached
  help: move git-diff and git-reset to different groups

 .gitignore                             |   1 +
 Documentation/config/interactive.txt   |   3 +-
 Documentation/git-checkout.txt         |   3 +-
 Documentation/git-clean.txt            |   2 +-
 Documentation/git-commit.txt           |   2 +-
 Documentation/git-format-patch.txt     |   2 +-
 Documentation/git-reset.txt            |  13 +-
 Documentation/git-restore.txt (new)    | 183 +++++++++++++++
 Documentation/git-revert.txt           |   7 +-
 Documentation/git-rm.txt               |   7 +-
 Documentation/git.txt                  |  20 ++
 Documentation/gitcli.txt               |   4 +-
 Documentation/giteveryday.txt          |   5 +-
 Documentation/gittutorial-2.txt        |   4 +-
 Documentation/gittutorial.txt          |   2 +-
 Documentation/user-manual.txt          |  14 +-
 Makefile                               |   1 +
 builtin.h                              |   1 +
 builtin/checkout.c                     | 299 +++++++++++++++++++------
 builtin/clone.c                        |   2 +-
 builtin/commit.c                       |   2 +-
 builtin/rm.c                           |   7 +-
 command-list.txt                       |   7 +-
 contrib/completion/git-completion.bash |  15 ++
 git-add--interactive.perl              |  52 +++++
 git.c                                  |   1 +
 t/lib-patch-mode.sh                    |  12 +
 t/t2070-restore.sh (new +x)            |  99 ++++++++
 t/t2071-restore-patch.sh (new +x)      | 110 +++++++++
 t/t3600-rm.sh                          |   6 +-
 t/t7508-status.sh                      |  84 +++----
 t/t7512-status-help.sh                 |  20 +-
 wt-status.c                            |  30 ++-
 33 files changed, 848 insertions(+), 172 deletions(-)
 create mode 100644 Documentation/git-restore.txt
 create mode 100755 t/t2070-restore.sh
 create mode 100755 t/t2071-restore-patch.sh

Diff:

diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index ee0d164d0e..a294652dd6 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -570,7 +570,7 @@ $ git add frotz
 
 SEE ALSO
 --------
-linkgit:git-switch[1]
+linkgit:git-switch[1],
 linkgit:git-restore[1]
 
 GIT
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index e7ac8eb9e8..7628193284 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -56,7 +56,7 @@ summary of what is included by any of the above for the next
 commit by giving the same set of parameters (options and paths).
 
 If you make a commit and then find a mistake immediately after
-that, you can recover from it with 'git restore' or 'git reset'.
+that, you can recover from it with 'git reset'.
 
 
 OPTIONS
@@ -359,7 +359,7 @@ When recording your own work, the contents of modified 
files in
 your working tree are temporarily stored to a staging area
 called the "index" with 'git add'.  A file can be
 reverted back, only in the index but not in the working tree,
-to that of the last commit with `git restore --index <file>`,
+to that of the last commit with `git restore --staged <file>`,
 which effectively reverts 'git add' and prevents the changes to
 this file from participating in the next commit.  After building
 the state to be committed incrementally with these commands,
diff --git a/Documentation/git-format-patch.txt 
b/Documentation/git-format-patch.txt
index 71c9fe3af3..01bfcecf69 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -422,7 +422,7 @@ One way to test if your MUA is set up correctly is:
 
     $ git fetch <project> master:test-apply
     $ git switch test-apply
-    $ git restore --source=HEAD --index --worktree :/
+    $ git restore --source=HEAD --staged --worktree :/
     $ git am a.patch
 
 If it does not apply correctly, there can be various reasons.
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index b70281677f..633d71d36a 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -25,7 +25,8 @@ The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.
        the current branch.)
 +
 This means that `git reset <paths>` is the opposite of `git add
-<paths>`.
+<paths>`. This command is equivalent to
+`git restore [--source=<tree-ish>] --staged <paths>...`.
 +
 After running `git reset <paths>` to update the index entry, you can
 use linkgit:git-restore[1] to check the contents out of the index to
@@ -86,8 +87,8 @@ but carries forward unmerged index entries.
        changes, reset is aborted.
 --
 
-If you want to undo a commit other than the latest on a branch,
-linkgit:git-revert[1] is your friend.
+See "Reset, restore and revert" in linkgit:git[1] for the differences
+between the three commands.
 
 
 OPTIONS
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index a667a5ced4..b608f3f360 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -8,48 +8,60 @@ git-restore - Restore working tree files
 SYNOPSIS
 --------
 [verse]
-'git restore' [<options>] [--source=<revision>] <pathspec>...
-'git restore' (-p|--patch) [--source=<revision>] [<pathspec>...]
+'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] 
<pathspec>...
+'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] 
[--worktree] [<pathspec>...]
 
 DESCRIPTION
 -----------
-Restore paths in the working tree by replacing with the contents in
-the restore source or remove if the paths do not exist in the restore
-source. The source is by default the index but could be from a commit.
-The command can also optionally restore content in the index from a
-commit.
+Restore specified paths in the working tree with some contents from a
+restore source. If a path is tracked but does not exist in the restore
+source, it will be removed to match the source.
 
-When a `<revision>` is given, the paths that match the `<pathspec>` are
-updated both in the index and in the working tree.
+The command can also be used to restore the content in the index with
+`--staged`, or restore both the working tree and the index with
+`--staged --worktree`.
+
+By default, the restore sources for working tree and the index are the
+index and `HEAD` respectively. `--source` could be used to specify a
+commit as the restore source.
+
+See "Reset, restore and revert" in linkgit:git[1] for the differences
+between the three commands.
 
 OPTIONS
 -------
--s<tree>::
+-s <tree>::
 --source=<tree>::
        Restore the working tree files with the content from the given
-       tree or any revision that leads to a tree (e.g. a commit or a
-       branch).
+       tree. It is common to specify the source tree by naming a
+       commit, branch or tag associated with it.
++
+If not specified, the default restore source for the working tree is
+the index, and the default restore source for the index index is
+`HEAD`. When both `--staged` and `--worktree` are specified,
+`--source` must also be specified.
 
 -p::
 --patch::
        Interactively select hunks in the difference between the
-       `<revision>` (or the index, if unspecified) and the working
-       tree. See the ``Interactive Mode'' section of linkgit:git-add[1]
-       to learn how to operate the `--patch` mode.
+       restore source and the restore location. See the ``Interactive
+       Mode'' section of linkgit:git-add[1] to learn how to operate
+       the `--patch` mode.
++
+Note that `--patch` can accept no pathspec and will prompt to restore
+all modified paths.
 
 -W::
 --worktree::
--I::
---index::
+-S::
+--staged::
        Specify the restore location. If neither option is specified,
-       by default the working tree is restored. If `--index` is
-       specified without `--worktree` or `--source`, `--source=HEAD`
-       is implied. These options only make sense to use with
-       `--source`.
+       by default the working tree is restored. Specifying `--staged`
+       will only restore the index. Specifying both restores both.
 
 -q::
 --quiet::
-       Quiet, suppress feedback messages.
+       Quiet, suppress feedback messages. Implies `--no-progress`.
 
 --progress::
 --no-progress::
@@ -58,16 +70,10 @@ OPTIONS
        is specified. This flag enables progress reporting even if not
        attached to a terminal, regardless of `--quiet`.
 
--f::
---force::
-       If `--source` is not specified, unmerged entries are left alone
-       and will not fail the operation. Unmerged entries are always
-       replaced if `--source` is specified, regardless of `--force`.
-
 --ours::
 --theirs::
-       Check out stage #2 ('ours') or #3 ('theirs') for unmerged
-       paths.
+       When restoring files in the working tree from the index, use
+       stage #2 ('ours') or #3 ('theirs') for unmerged paths.
 +
 Note that during `git rebase` and `git pull --rebase`, 'ours' and
 'theirs' may appear swapped. See the explanation of the same options
@@ -75,67 +81,64 @@ in linkgit:git-checkout[1] for details.
 
 -m::
 --merge::
-       Recreate the conflicted merge in the specified paths.
+       When restoring files on the working tree from the index,
+       recreate the conflicted merge in the unmerged paths.
 
 --conflict=<style>::
        The same as `--merge` option above, but changes the way the
-       conflicting hunks are presented, overriding the merge.conflictStyle
-       configuration variable.  Possible values are "merge" (default)
-       and "diff3" (in addition to what is shown by "merge" style,
-       shows the original contents).
+       conflicting hunks are presented, overriding the
+       `merge.conflictStyle` configuration variable.  Possible values
+       are "merge" (default) and "diff3" (in addition to what is
+       shown by "merge" style, shows the original contents).
+
+--ignore-unmerged::
+       When restoring files on the working tree from the index, do
+       not abort the operation if there are unmerged entries and
+       neither `--ours`, `--theirs`, `--merge` or `--conflict` is
+       specified. Unmerged paths on the working tree are left alone.
 
 --ignore-skip-worktree-bits::
-       In sparse checkout mode, by default update only entries
+       In sparse checkout mode, by default is to only update entries
        matched by `<pathspec>` and sparse patterns in
        $GIT_DIR/info/sparse-checkout. This option ignores the sparse
-       patterns and unconditionally restores any files in `<pathspec>`.
-
---recurse-submodules::
---no-recurse-submodules::
-       Using `--recurse-submodules` will update the content of all initialized
-       submodules according to the commit recorded in the superproject. If
-       local modifications in a submodule would be overwritten the checkout
-       will fail unless `-f` is used. If nothing (or `--no-recurse-submodules`)
-       is used, the work trees of submodules will not be updated.
-       Just like linkgit:git-submodule[1], this will detach the
-       submodules HEAD.
+       patterns and unconditionally restores any files in
+       `<pathspec>`.
 
 --overlay::
 --no-overlay::
-       In overlay mode, `git checkout` never removes files from the
-       index or the working tree. In no-overlay mode, files that
-       appear in the index and working tree, but not in `--source` tree
-       are removed, to make them match `<tree-ish>` exactly. The
-       default is no-overlay mode.
+       In overlay mode, the command never removes files when
+       restoring. In no-overlay mode, tracked files that do not
+       appear in the `--source` tree are removed, to make them match
+       `<tree>` exactly. The default is no-overlay mode.
 
 EXAMPLES
 --------
 
-The following sequence checks out the `master` branch, reverts
-the `Makefile` to two revisions back, deletes hello.c by
-mistake, and gets it back from the index.
+The following sequence switches to the `master` branch, reverts the
+`Makefile` to two revisions back, deletes hello.c by mistake, and gets
+it back from the index.
 
 ------------
 $ git switch master
 $ git restore --source master~2 Makefile  <1>
 $ rm -f hello.c
-$ git restore hello.c                   <2>
+$ git restore hello.c                     <2>
 ------------
 
 <1> take a file out of another commit
 <2> restore hello.c from the index
 
-If you want to check out _all_ C source files out of the index,
-you can say
+If you want to restore _all_ C source files to match the version in
+the index, you can say
 
 ------------
 $ git restore '*.c'
 ------------
 
 Note the quotes around `*.c`.  The file `hello.c` will also be
-checked out, even though it is no longer in the working tree,
-because the file globbing is used to match entries in the index
-(not in the working tree by the shell).
+restored, even though it is no longer in the working tree, because the
+file globbing is used to match entries in the index (not in the
+working tree by the shell).
 
 To restore all files in the current directory
 
@@ -144,28 +147,36 @@ $ git restore .
 ------------
 
 or to restore all working tree files with 'top' pathspec magic (see
-linkgit::gitglossary[7])
+linkgit:gitglossary[7])
 
 ------------
 $ git restore :/
 ------------
 
-To restore a file in the index only (this is the same as using
-"git reset")
+To restore a file in the index to match the version in `HEAD` (this is
+the same as using linkgit:git-reset[1])
+
+------------
+$ git restore --staged hello.c
+------------
+
+or you can restore both the index and the working tree (this the same
+as using linkgit:git-checkout[1])
 
 ------------
-$ git restore --index hello.c
+$ git restore --source=HEAD --staged --worktree hello.c
 ------------
 
-or you can restore both the index and the working tree
+or the short form which is more practical but less readable:
 
 ------------
-$ git restore --source=HEAD --index --worktree hello.c
+$ git restore -s@ -SW hello.c
 ------------
 
 SEE ALSO
 --------
-linkgit:git-checkout[1]
+linkgit:git-checkout[1],
+linkgit:git-reset[1]
 
 GIT
 ---
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index c38bc54439..9aadc36881 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -27,9 +27,12 @@ throw away all uncommitted changes in your working 
directory, you
 should see linkgit:git-reset[1], particularly the `--hard` option.  If
 you want to extract specific files as they were in another commit, you
 should see linkgit:git-restore[1], specifically the `--source`
-option  Take care with these alternatives as
+option. Take care with these alternatives as
 both will discard uncommitted changes in your working directory.
 
+See "Reset, restore and revert" in linkgit:git[1] for the differences
+between the three commands.
+
 OPTIONS
 -------
 <commit>...::
diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index b5c46223c4..4271fc5eaa 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -8,7 +8,7 @@ git-rm - Remove files from the working tree and from the index
 SYNOPSIS
 --------
 [verse]
-'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] 
<file>...
+'git rm' [-f | --force] [-n] [-r] [--staged] [--ignore-unmatch] [--quiet] [--] 
<file>...
 
 DESCRIPTION
 -----------
@@ -55,10 +55,11 @@ OPTIONS
        the list of files, (useful when filenames might be mistaken
        for command-line options).
 
+--staged::
 --cached::
        Use this option to unstage and remove paths only from the index.
-       Working tree files, whether modified or not, will be
-       left alone.
+       Working tree files, whether modified or not, will be left
+       alone. `--cached` is synonym for `--staged`.
 
 --ignore-unmatch::
        Exit with a zero status even if no files matched.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 00156d64aa..fbed007354 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -210,6 +210,26 @@ people via patch over e-mail.
 
 include::cmds-foreignscminterface.txt[]
 
+Reset, restore and revert
+~~~~~~~~~~~~~~~~~~~~~~~~~
+There are three commands with similar names: `git reset`,
+`git restore` and `git revert`.
+
+* linkgit:git-revert[1] is about making a new commit that reverts the
+  changes made by other commits.
+
+* linkgit:git-restore[1] is about restoring files in the working tree
+  from either the index or another commit. This command does not
+  update your branch. The command can also be used to restore files in
+  the index from another commit.
+
+* linkgit:git-reset[1] is about updating your branch, moving the tip
+  in order to add or remove commits from the branch. This operation
+  changes the commit history.
++
+`git reset` can also be used to restore the index, overlapping with
+`git restore`.
+
 
 Low-level commands (plumbing)
 -----------------------------
diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt
index 79517b22f9..1bd919f92b 100644
--- a/Documentation/giteveryday.txt
+++ b/Documentation/giteveryday.txt
@@ -51,8 +51,7 @@ following commands.
 
   * linkgit:git-commit[1] to advance the current branch.
 
-  * linkgit:git-reset[1] and linkgit:git-restore[1] (with
-    pathname parameters) to undo changes.
+  * linkgit:git-restore[1] to undo changes.
 
   * linkgit:git-merge[1] to merge between local branches.
 
diff --git a/Documentation/gittutorial-2.txt b/Documentation/gittutorial-2.txt
index e412841488..8bdb7d0bd3 100644
--- a/Documentation/gittutorial-2.txt
+++ b/Documentation/gittutorial-2.txt
@@ -370,7 +370,7 @@ situation:
 $ git status
 On branch master
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   closing.txt
 
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index 6266ca21b4..59ef5cef1f 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -110,7 +110,7 @@ $ git status
 On branch master
 Changes to be committed:
 Your branch is up to date with 'origin/master'.
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   file1
        modified:   file2
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 02713886f0..8bce75b2cf 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1446,7 +1446,7 @@ mistake, you can return the entire working tree to the 
last committed
 state with
 
 -------------------------------------------------
-$ git restore --index --worktree :/
+$ git restore --staged --worktree :/
 -------------------------------------------------
 
 If you make a commit that you later wish you hadn't, there are two
diff --git a/builtin/checkout.c b/builtin/checkout.c
index e8896ddbca..bed79ae595 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -38,7 +38,7 @@ static const char * const switch_branch_usage[] = {
        NULL,
 };
 
-static const char * const restore_files_usage[] = {
+static const char * const restore_usage[] = {
        N_("git restore [<options>] [--source=<branch>] <file>..."),
        NULL,
 };
@@ -68,6 +68,8 @@ struct checkout_opts {
        int empty_pathspec_ok;
        int checkout_index;
        int checkout_worktree;
+       const char *ignore_unmerged_opt;
+       int ignore_unmerged;
 
        const char *new_branch;
        const char *new_branch_force;
@@ -409,8 +411,9 @@ static int checkout_paths(const struct checkout_opts *opts,
        if (opts->new_branch_log)
                die(_("'%s' cannot be used with updating paths"), "-l");
 
-       if (opts->force && opts->patch_mode)
-               die(_("'%s' cannot be used with updating paths"), "-f");
+       if (opts->ignore_unmerged && opts->patch_mode)
+               die(_("'%s' cannot be used with updating paths"),
+                   opts->ignore_unmerged_opt);
 
        if (opts->force_detach)
                die(_("'%s' cannot be used with updating paths"), "--detach");
@@ -418,8 +421,9 @@ static int checkout_paths(const struct checkout_opts *opts,
        if (opts->merge && opts->patch_mode)
                die(_("'%s' cannot be used with %s"), "--merge", "--patch");
 
-       if (opts->force && opts->merge)
-               die(_("'%s' cannot be used with %s"), "-f", "-m");
+       if (opts->ignore_unmerged && opts->merge)
+               die(_("'%s' cannot be used with %s"),
+                   opts->ignore_unmerged_opt, "-m");
 
        if (opts->new_branch)
                die(_("Cannot update paths and switch to branch '%s' at the 
same time."),
@@ -427,12 +431,22 @@ static int checkout_paths(const struct checkout_opts 
*opts,
 
        if (!opts->checkout_worktree && !opts->checkout_index)
                die(_("neither '%s' or '%s' is specified"),
-                   "--index", "--worktree");
+                   "--staged", "--worktree");
 
-       if (!opts->source_tree && !opts->checkout_worktree)
+       if (!opts->checkout_worktree && !opts->from_treeish)
                die(_("'%s' must be used when '%s' is not specified"),
                    "--worktree", "--source");
 
+       if (opts->checkout_index && !opts->checkout_worktree &&
+           opts->writeout_stage)
+               die(_("'%s' or '%s' cannot be used with %s"),
+                   "--ours", "--theirs", "--staged");
+
+       if (opts->checkout_index && !opts->checkout_worktree &&
+           opts->merge)
+               die(_("'%s' or '%s' cannot be used with %s"),
+                   "--merge", "--conflict", "--staged");
+
        if (opts->patch_mode) {
                const char *patch_mode;
 
@@ -443,7 +457,8 @@ static int checkout_paths(const struct checkout_opts *opts,
                else if (!opts->checkout_index && opts->checkout_worktree)
                        patch_mode = "--patch=worktree";
                else
-                       BUG("either flag must have been set");
+                       BUG("either flag must have been set, worktree=%d, 
index=%d",
+                           opts->checkout_worktree, opts->checkout_index);
                return run_add_interactive(revision, patch_mode, 
&opts->pathspec);
        }
 
@@ -486,8 +501,9 @@ static int checkout_paths(const struct checkout_opts *opts,
                if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce))
                                continue;
-                       if (opts->force) {
-                               warning(_("path '%s' is unmerged"), ce->name);
+                       if (opts->ignore_unmerged) {
+                               if (!opts->quiet)
+                                       warning(_("path '%s' is unmerged"), 
ce->name);
                        } else if (opts->writeout_stage) {
                                errs |= check_stage(opts->writeout_stage, ce, 
pos, opts->overlay_mode);
                        } else if (opts->merge) {
@@ -1405,8 +1421,6 @@ static struct option *add_common_options(struct 
checkout_opts *opts,
                            "checkout", "control recursive updating of 
submodules",
                            PARSE_OPT_OPTARG, 
option_parse_recurse_submodules_worktree_updater },
                OPT_BOOL(0, "progress", &opts->show_progress, N_("force 
progress reporting")),
-               OPT__FORCE(&opts->force, N_("force checkout (throw away local 
modifications)"),
-                          PARSE_OPT_NOCOMPLETE),
                OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge 
with the new branch")),
                OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
                           N_("conflict style (merge or diff3)")),
@@ -1424,6 +1438,8 @@ static struct option *add_common_switch_branch_options(
                OPT_BOOL('d', "detach", &opts->force_detach, N_("detach HEAD at 
named commit")),
                OPT_SET_INT('t', "track",  &opts->track, N_("set upstream info 
for new branch"),
                        BRANCH_TRACK_EXPLICIT),
+               OPT__FORCE(&opts->force, N_("force checkout (throw away local 
modifications)"),
+                          PARSE_OPT_NOCOMPLETE),
                OPT_STRING(0, "orphan", &opts->new_orphan_branch, 
N_("new-branch"), N_("new unparented branch")),
                OPT_BOOL_F(0, "overwrite-ignore", &opts->overwrite_ignore,
                           N_("update ignored files (default)"),
@@ -1493,8 +1509,11 @@ static int checkout_main(int argc, const char **argv, 
const char *prefix,
                opts->merge = 1; /* implied */
                git_xmerge_config("merge.conflictstyle", opts->conflict_style, 
NULL);
        }
-       if (opts->force)
+       if (opts->force) {
                opts->discard_changes = 1;
+               opts->ignore_unmerged_opt = "--force";
+               opts->ignore_unmerged = 1;
+       }
 
        if ((!!opts->new_branch + !!opts->new_branch_force + 
!!opts->new_orphan_branch) > 1)
                die(_("-b, -B and --orphan are mutually exclusive"));
@@ -1516,8 +1535,8 @@ static int checkout_main(int argc, const char **argv, 
const char *prefix,
        if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
                BUG("these flags should be non-negative by now");
        /*
-        * convenient shortcut: "git restore --index" equals
-        * "git restore --index --source HEAD"
+        * convenient shortcut: "git restore --staged" equals
+        * "git restore --staged --source HEAD"
         */
        if (!opts->from_treeish && opts->checkout_index && 
!opts->checkout_worktree)
                opts->from_treeish = "HEAD";
@@ -1587,7 +1606,7 @@ static int checkout_main(int argc, const char **argv, 
const char *prefix,
 
        if (opts->accept_pathspec && !opts->empty_pathspec_ok && !argc &&
            !opts->patch_mode)  /* patch mode is special */
-               die(_("pathspec is required"));
+               die(_("you must specify path(s) to restore"));
 
        if (argc) {
                parse_pathspec(&opts->pathspec, 0,
@@ -1737,10 +1756,12 @@ int cmd_restore(int argc, const char **argv, const char 
*prefix)
        struct option restore_options[] = {
                OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
                           N_("where the checkout from")),
-               OPT_BOOL('I', "index", &opts.checkout_index,
+               OPT_BOOL('S', "staged", &opts.checkout_index,
                           N_("restore the index")),
                OPT_BOOL('W', "worktree", &opts.checkout_worktree,
                           N_("restore the working tree (default)")),
+               OPT_BOOL(0, "ignore-unmerged", &opts.ignore_unmerged,
+                        N_("ignore unmerged entries")),
                OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay 
mode")),
                OPT_END()
        };
@@ -1753,13 +1774,14 @@ int cmd_restore(int argc, const char **argv, const char 
*prefix)
        opts.overlay_mode = 0;
        opts.checkout_index = -1;    /* default off */
        opts.checkout_worktree = -2; /* default on */
+       opts.ignore_unmerged_opt = "--ignore-unmerged";
 
        options = parse_options_dup(restore_options);
        options = add_common_options(&opts, options);
        options = add_checkout_path_options(&opts, options);
 
        ret = checkout_main(argc, argv, prefix, &opts,
-                           options, restore_files_usage);
+                           options, restore_usage);
        FREE_AND_NULL(options);
        return ret;
 }
diff --git a/builtin/commit.c b/builtin/commit.c
index c530264e63..fa5982cc86 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1676,7 +1676,7 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
        if (commit_index_files())
                die(_("repository has been updated, but unable to write\n"
                      "new_index file. Check that disk is not full and quota 
is\n"
-                     "not exceeded, and then \"git restore --index :/\" to 
recover."));
+                     "not exceeded, and then \"git restore --staged :/\" to 
recover."));
 
        if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
                write_commit_graph_reachable(get_object_directory(), 0, 0);
diff --git a/builtin/rm.c b/builtin/rm.c
index db85b33982..47c8eb100b 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -217,7 +217,7 @@ static int check_local_mod(struct object_id *head, int 
index_only)
                             "staged in the index:",
                             "the following files have changes "
                             "staged in the index:", files_cached.nr),
-                         _("\n(use --cached to keep the file,"
+                         _("\n(use --staged to keep the file,"
                            " or -f to force removal)"),
                          &errs);
        string_list_clear(&files_cached, 0);
@@ -226,7 +226,7 @@ static int check_local_mod(struct object_id *head, int 
index_only)
                          Q_("the following file has local modifications:",
                             "the following files have local modifications:",
                             files_local.nr),
-                         _("\n(use --cached to keep the file,"
+                         _("\n(use --staged to keep the file,"
                            " or -f to force removal)"),
                          &errs);
        string_list_clear(&files_local, 0);
@@ -240,7 +240,8 @@ static int ignore_unmatch = 0;
 static struct option builtin_rm_options[] = {
        OPT__DRY_RUN(&show_only, N_("dry run")),
        OPT__QUIET(&quiet, N_("do not list removed files")),
-       OPT_BOOL( 0 , "cached",         &index_only, N_("only remove from the 
index")),
+       OPT_BOOL( 0 , "staged",         &index_only, N_("only remove from the 
index")),
+       OPT_BOOL( 0 , "cached",         &index_only, N_("synonym for 
--staged")),
        OPT__FORCE(&force, N_("override the up-to-date check"), 
PARSE_OPT_NOCOMPLETE),
        OPT_BOOL('r', NULL,             &recursive,  N_("allow recursive 
removal")),
        OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
diff --git a/command-list.txt b/command-list.txt
index cf8dccb439..a9ac72bef4 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -81,7 +81,7 @@ git-cvsimport                           foreignscminterface
 git-cvsserver                           foreignscminterface
 git-daemon                              synchingrepositories
 git-describe                            mainporcelain
-git-diff                                mainporcelain           history
+git-diff                                mainporcelain           info
 git-diff-files                          plumbinginterrogators
 git-diff-index                          plumbinginterrogators
 git-diff-tree                           plumbinginterrogators
@@ -150,7 +150,7 @@ git-repack                              
ancillarymanipulators           complete
 git-replace                             ancillarymanipulators           
complete
 git-request-pull                        foreignscminterface             
complete
 git-rerere                              ancillaryinterrogators
-git-reset                               mainporcelain           worktree
+git-reset                               mainporcelain           history
 git-restore                             mainporcelain           worktree
 git-revert                              mainporcelain
 git-rev-list                            plumbinginterrogators
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index df91bf54bc..73ea13ede9 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -23,11 +23,6 @@ test_expect_success 'restore without pathspec is not ok' '
        test_must_fail git restore --source=first
 '
 
-test_expect_success 'restore -p without pathspec is fine' '
-       echo q >cmd &&
-       git restore -p <cmd
-'
-
 test_expect_success 'restore a file, ignoring branch of same name' '
        cat one >expected &&
        echo dirty >>one &&
@@ -35,7 +30,7 @@ test_expect_success 'restore a file, ignoring branch of same 
name' '
        test_cmp expected one
 '
 
-test_expect_success 'restore a file on worktree from another branch' '
+test_expect_success 'restore a file on worktree from another ref' '
        test_when_finished git reset --hard &&
        git cat-file blob first:./first.t >expected &&
        git restore --source=first first.t &&
@@ -45,33 +40,60 @@ test_expect_success 'restore a file on worktree from 
another branch' '
        test_cmp expected actual
 '
 
-test_expect_success 'restore a file in the index from another branch' '
+test_expect_success 'restore a file in the index from another ref' '
        test_when_finished git reset --hard &&
        git cat-file blob first:./first.t >expected &&
-       git restore --source=first --index first.t &&
+       git restore --source=first --staged first.t &&
        git show :first.t >actual &&
        test_cmp expected actual &&
        git cat-file blob HEAD:./first.t >expected &&
        test_cmp expected first.t
 '
 
-test_expect_success 'restore a file in both the index and worktree from 
another branch' '
+test_expect_success 'restore a file in both the index and worktree from 
another ref' '
        test_when_finished git reset --hard &&
        git cat-file blob first:./first.t >expected &&
-       git restore --source=first --index --worktree first.t &&
+       git restore --source=first --staged --worktree first.t &&
        git show :first.t >actual &&
        test_cmp expected actual &&
        test_cmp expected first.t
 '
 
-test_expect_success 'restore --index uses HEAD as source' '
+test_expect_success 'restore --staged uses HEAD as source' '
        test_when_finished git reset --hard &&
        git cat-file blob :./first.t >expected &&
        echo index-dirty >>first.t &&
        git add first.t &&
-       git restore --index first.t &&
+       git restore --staged first.t &&
        git cat-file blob :./first.t >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'restore --ignore-unmerged ignores unmerged entries' '
+       git init unmerged &&
+       (
+               cd unmerged &&
+               echo one >unmerged &&
+               echo one >common &&
+               git add unmerged common &&
+               git commit -m common &&
+               git switch -c first &&
+               echo first >unmerged &&
+               git commit -am first &&
+               git switch -c second master &&
+               echo second >unmerged &&
+               git commit -am second &&
+               test_must_fail git merge first &&
+
+               echo dirty >>common &&
+               test_must_fail git restore . &&
+
+               git restore --ignore-unmerged --quiet . >output 2>&1 &&
+               git diff common >diff-output &&
+               : >empty &&
+               test_cmp empty output &&
+               test_cmp empty diff-output
+       )
+'
+
 test_done
diff --git a/t/t2071-restore-patch.sh b/t/t2071-restore-patch.sh
index 46ebcb2413..98b2476e7c 100755
--- a/t/t2071-restore-patch.sh
+++ b/t/t2071-restore-patch.sh
@@ -16,6 +16,11 @@ test_expect_success PERL 'setup' '
        save_head
 '
 
+test_expect_success PERL 'restore -p without pathspec is fine' '
+       echo q >cmd &&
+       git restore -p <cmd
+'
+
 # note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar'
 
 test_expect_success PERL 'saying "n" does nothing' '
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 04e5d42bd3..5686032b8c 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -797,7 +797,7 @@ test_expect_success 'rm file with local modification' '
        cat >expect <<-\EOF &&
        error: the following file has local modifications:
            foo.txt
-       (use --cached to keep the file, or -f to force removal)
+       (use --staged to keep the file, or -f to force removal)
        EOF
        git commit -m "testing rm 3" &&
        echo content3 >foo.txt &&
@@ -819,7 +819,7 @@ test_expect_success 'rm file with changes in the index' '
        cat >expect <<-\EOF &&
        error: the following file has changes staged in the index:
            foo.txt
-       (use --cached to keep the file, or -f to force removal)
+       (use --staged to keep the file, or -f to force removal)
        EOF
        git reset --hard &&
        echo content5 >foo.txt &&
@@ -845,7 +845,7 @@ test_expect_success 'rm files with two different errors' '
        (use -f to force removal)
        error: the following file has changes staged in the index:
            bar1.txt
-       (use --cached to keep the file, or -f to force removal)
+       (use --staged to keep the file, or -f to force removal)
        EOF
        echo content >foo1.txt &&
        git add foo1.txt &&
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index d5cf0185b7..738f3df2f9 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -71,7 +71,7 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'status (1)' '
-       test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
+       test_i18ngrep "use \"git rm --staged <file>\.\.\.\" to unstage" output
 '
 
 strip_comments () {
@@ -94,7 +94,7 @@ test_expect_success 'status --column' '
 #   (use "git pull" to merge the remote branch into yours)
 #
 # Changes to be committed:
-#   (use "git restore --index <file>..." to unstage)
+#   (use "git restore --staged <file>..." to unstage)
 #
 #      new file:   dir2/added
 #
@@ -128,7 +128,7 @@ cat >expect <<\EOF
 #   (use "git pull" to merge the remote branch into yours)
 #
 # Changes to be committed:
-#   (use "git restore --index <file>..." to unstage)
+#   (use "git restore --staged <file>..." to unstage)
 #
 #      new file:   dir2/added
 #
@@ -278,7 +278,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
 
@@ -347,7 +347,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
 
@@ -420,7 +420,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
 
@@ -484,7 +484,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
 
@@ -542,7 +542,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
 
@@ -605,7 +605,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   ../dir2/added
 
@@ -676,7 +676,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        <GREEN>new file:   dir2/added<RESET>
 
@@ -802,7 +802,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
 
@@ -852,7 +852,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   dir1/modified
 
@@ -896,7 +896,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
        new file:   sm
@@ -956,7 +956,7 @@ and have 1 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        new file:   dir2/added
        new file:   sm
@@ -1068,7 +1068,7 @@ and have 2 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --source=HEAD^1 --index <file>..." to unstage)
+  (use "git restore --source=HEAD^1 --staged <file>..." to unstage)
 
        new file:   dir2/added
        new file:   sm
@@ -1123,7 +1123,7 @@ and have 2 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   sm
 
@@ -1235,7 +1235,7 @@ and have 2 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   sm
 
@@ -1295,7 +1295,7 @@ and have 2 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   sm
 
@@ -1379,7 +1379,7 @@ cat > expect << EOF
 ;   (use "git pull" to merge the remote branch into yours)
 ;
 ; Changes to be committed:
-;   (use "git restore --index <file>..." to unstage)
+;   (use "git restore --staged <file>..." to unstage)
 ;
 ;      modified:   sm
 ;
@@ -1458,7 +1458,7 @@ and have 2 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   sm
 
@@ -1581,7 +1581,7 @@ and have 2 and 2 different commits each, respectively.
   (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   sm
 
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index 6e678456bc..1b9712c675 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -85,7 +85,7 @@ You are currently rebasing branch '\''rebase_conflicts'\'' on 
'\''$ONTO'\''.
   (use "git rebase --abort" to check out the original branch)
 
 Unmerged paths:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
   (use "git add <file>..." to mark resolution)
 
        both modified:   main.txt
@@ -110,7 +110,7 @@ You are currently rebasing branch '\''rebase_conflicts'\'' 
on '\''$ONTO'\''.
   (all conflicts fixed: run "git rebase --continue")
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   main.txt
 
@@ -148,7 +148,7 @@ You are currently rebasing branch 
'\''rebase_i_conflicts_second'\'' on '\''$ONTO
   (use "git rebase --abort" to check out the original branch)
 
 Unmerged paths:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
   (use "git add <file>..." to mark resolution)
 
        both modified:   main.txt
@@ -176,7 +176,7 @@ You are currently rebasing branch 
'\''rebase_i_conflicts_second'\'' on '\''$ONTO
   (all conflicts fixed: run "git rebase --continue")
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   main.txt
 
@@ -816,7 +816,7 @@ You are currently reverting commit $TO_REVERT.
   (use "git revert --abort" to cancel the revert operation)
 
 Unmerged paths:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
   (use "git add <file>..." to mark resolution)
 
        both modified:   to-revert.txt
@@ -837,7 +837,7 @@ You are currently reverting commit $TO_REVERT.
   (use "git revert --abort" to cancel the revert operation)
 
 Changes to be committed:
-  (use "git restore --index <file>..." to unstage)
+  (use "git restore --staged <file>..." to unstage)
 
        modified:   to-revert.txt
 
diff --git a/wt-status.c b/wt-status.c
index 3098e77d72..4d065ce89e 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -181,13 +181,13 @@ static void wt_longstatus_print_unmerged_header(struct 
wt_status *s)
        else if (!s->is_initial) {
                if (!strcmp(s->reference, "HEAD"))
                        status_printf_ln(s, c,
-                                        _("  (use \"git restore --index 
<file>...\" to unstage)"));
+                                        _("  (use \"git restore --staged 
<file>...\" to unstage)"));
                else
                        status_printf_ln(s, c,
-                                        _("  (use \"git restore --source=%s 
--index <file>...\" to unstage)"),
+                                        _("  (use \"git restore --source=%s 
--staged <file>...\" to unstage)"),
                                         s->reference);
        } else
-               status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" 
to unstage)"));
+               status_printf_ln(s, c, _("  (use \"git rm --staged <file>...\" 
to unstage)"));
 
        if (!both_deleted) {
                if (!del_mod_conflict)
@@ -214,13 +214,13 @@ static void wt_longstatus_print_cached_header(struct 
wt_status *s)
        else if (!s->is_initial) {
                if (!strcmp(s->reference, "HEAD"))
                        status_printf_ln(s, c
-                                        , _("  (use \"git restore --index 
<file>...\" to unstage)"));
+                                        , _("  (use \"git restore --staged 
<file>...\" to unstage)"));
                else
                        status_printf_ln(s, c,
-                                        _("  (use \"git restore --source=%s 
--index <file>...\" to unstage)"),
+                                        _("  (use \"git restore --source=%s 
--staged <file>...\" to unstage)"),
                                         s->reference);
        } else
-               status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" 
to unstage)"));
+               status_printf_ln(s, c, _("  (use \"git rm --staged <file>...\" 
to unstage)"));
        status_printf_ln(s, c, "%s", "");
 }
 


-- 
2.21.0.682.g30d2204636

Reply via email to