checkout: split part of it to new command 'restore'

Previously the switching branch business of 'git checkout' becomes a new command 'switch'. This adds the restore command for the checking out paths path. Similar to git-switch, a new man page is added to describe what the command will become. The implementation will be updated shortly to match the man page. A couple main differences from 'git checkout <paths>': - 'restore' by default will only update worktree. This matters more when --source is specified ('checkout <tree> <paths>' updates both worktree and index). - 'restore --staged' can be used to restore the index. This command overlaps with 'git reset <paths>'. - both worktree and index could also be restored at the same time (from a tree) when both --staged and --worktree are specified. This overlaps with 'git checkout <tree> <paths>' - default source for restoring worktree and index is the index and HEAD respectively. A different (tree) source could be specified as with --source (*). - when both index and worktree are restored, --source must be specified since the default source for these two individual targets are different (**) - --no-overlay is enabled by default, if an entry is missing in the source, restoring means deleting the entry (*) I originally went with --from instead of --source. I still think --from is a better name. The short option -f however is already taken by force. And I do think short option is good to have, e.g. to write -s@ or -s@^ instead of --source=HEAD. (**) If you sit down and think about it, moving worktree's source from the index to HEAD makes sense, but nobody is really thinking it through when they type the commands. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Apr 25, 2019 at 16:45 UTC 46e91b663badd99b3807ab34decfd32f3cbf15e7
13 files changed +257 -5
.gitignore
+1
@@ -143,6 +143,7 @@
143 /git-request-pull
144 /git-rerere
145 /git-reset
146 +/git-restore
147 /git-rev-list
148 /git-rev-parse
149 /git-revert
Documentation/config/interactive.txt
+2 -1
@@ -2,7 +2,8 @@ interactive.singleKey::
2 In interactive commands, allow the user to provide one-letter
3 input with a single key (i.e., without hitting enter).
4 Currently this is used by the `--patch` mode of
5 - linkgit:git-add[1], linkgit:git-checkout[1], linkgit:git-commit[1],
5 + linkgit:git-add[1], linkgit:git-checkout[1],
6 + linkgit:git-restore[1], linkgit:git-commit[1],
7 linkgit:git-reset[1], and linkgit:git-stash[1]. Note that this
8 setting is silently ignored if portable keystroke input
9 is not available; requires the Perl module Term::ReadKey.
Documentation/git-checkout.txt
+2 -1
@@ -570,7 +570,8 @@ $ git add frotz
570
571 SEE ALSO
572 --------
573 -linkgit:git-switch[1]
573 +linkgit:git-switch[1],
574 +linkgit:git-restore[1]
575
576 GIT
577 ---
Documentation/git-reset.txt
+4 -3
@@ -25,7 +25,8 @@ The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.
25 the current branch.)
26 +
27 This means that `git reset <paths>` is the opposite of `git add
28 -<paths>`.
28 +<paths>`. This command is equivalent to
29 +`git restore [--source=<tree-ish>] --staged <paths>...`.
30 +
31 After running `git reset <paths>` to update the index entry, you can
32 use linkgit:git-checkout[1] to check the contents out of the index to
@@ -86,8 +87,8 @@ but carries forward unmerged index entries.
87 changes, reset is aborted.
88 --
89
89 -If you want to undo a commit other than the latest on a branch,
90 -linkgit:git-revert[1] is your friend.
90 +See "Reset, restore and revert" in linkgit:git[1] for the differences
91 +between the three commands.
92
93
94 OPTIONS
Documentation/git-restore.txt new
+183
@@ -0,0 +1,183 @@
1 +git-restore(1)
2 +==============
3 +
4 +NAME
5 +----
6 +git-restore - Restore working tree files
7 +
8 +SYNOPSIS
9 +--------
10 +[verse]
11 +'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] <pathspec>...
12 +'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [<pathspec>...]
13 +
14 +DESCRIPTION
15 +-----------
16 +Restore specified paths in the working tree with some contents from a
17 +restore source. If a path is tracked but does not exist in the restore
18 +source, it will be removed to match the source.
19 +
20 +The command can also be used to restore the content in the index with
21 +`--staged`, or restore both the working tree and the index with
22 +`--staged --worktree`.
23 +
24 +By default, the restore sources for working tree and the index are the
25 +index and `HEAD` respectively. `--source` could be used to specify a
26 +commit as the restore source.
27 +
28 +See "Reset, restore and revert" in linkgit:git[1] for the differences
29 +between the three commands.
30 +
31 +OPTIONS
32 +-------
33 +-s <tree>::
34 +--source=<tree>::
35 + Restore the working tree files with the content from the given
36 + tree. It is common to specify the source tree by naming a
37 + commit, branch or tag associated with it.
38 ++
39 +If not specified, the default restore source for the working tree is
40 +the index, and the default restore source for the index index is
41 +`HEAD`. When both `--staged` and `--worktree` are specified,
42 +`--source` must also be specified.
43 +
44 +-p::
45 +--patch::
46 + Interactively select hunks in the difference between the
47 + restore source and the restore location. See the ``Interactive
48 + Mode'' section of linkgit:git-add[1] to learn how to operate
49 + the `--patch` mode.
50 ++
51 +Note that `--patch` can accept no pathspec and will prompt to restore
52 +all modified paths.
53 +
54 +-W::
55 +--worktree::
56 +-S::
57 +--staged::
58 + Specify the restore location. If neither option is specified,
59 + by default the working tree is restored. Specifying `--staged`
60 + will only restore the index. Specifying both restores both.
61 +
62 +-q::
63 +--quiet::
64 + Quiet, suppress feedback messages. Implies `--no-progress`.
65 +
66 +--progress::
67 +--no-progress::
68 + Progress status is reported on the standard error stream
69 + by default when it is attached to a terminal, unless `--quiet`
70 + is specified. This flag enables progress reporting even if not
71 + attached to a terminal, regardless of `--quiet`.
72 +
73 +--ours::
74 +--theirs::
75 + When restoring files in the working tree from the index, use
76 + stage #2 ('ours') or #3 ('theirs') for unmerged paths.
77 ++
78 +Note that during `git rebase` and `git pull --rebase`, 'ours' and
79 +'theirs' may appear swapped. See the explanation of the same options
80 +in linkgit:git-checkout[1] for details.
81 +
82 +-m::
83 +--merge::
84 + When restoring files on the working tree from the index,
85 + recreate the conflicted merge in the unmerged paths.
86 +
87 +--conflict=<style>::
88 + The same as `--merge` option above, but changes the way the
89 + conflicting hunks are presented, overriding the
90 + `merge.conflictStyle` configuration variable. Possible values
91 + are "merge" (default) and "diff3" (in addition to what is
92 + shown by "merge" style, shows the original contents).
93 +
94 +--ignore-unmerged::
95 + When restoring files on the working tree from the index, do
96 + not abort the operation if there are unmerged entries and
97 + neither `--ours`, `--theirs`, `--merge` or `--conflict` is
98 + specified. Unmerged paths on the working tree are left alone.
99 +
100 +--ignore-skip-worktree-bits::
101 + In sparse checkout mode, by default is to only update entries
102 + matched by `<pathspec>` and sparse patterns in
103 + $GIT_DIR/info/sparse-checkout. This option ignores the sparse
104 + patterns and unconditionally restores any files in
105 + `<pathspec>`.
106 +
107 +--overlay::
108 +--no-overlay::
109 + In overlay mode, the command never removes files when
110 + restoring. In no-overlay mode, tracked files that do not
111 + appear in the `--source` tree are removed, to make them match
112 + `<tree>` exactly. The default is no-overlay mode.
113 +
114 +EXAMPLES
115 +--------
116 +
117 +The following sequence switches to the `master` branch, reverts the
118 +`Makefile` to two revisions back, deletes hello.c by mistake, and gets
119 +it back from the index.
120 +
121 +------------
122 +$ git switch master
123 +$ git restore --source master~2 Makefile <1>
124 +$ rm -f hello.c
125 +$ git restore hello.c <2>
126 +------------
127 +
128 +<1> take a file out of another commit
129 +<2> restore hello.c from the index
130 +
131 +If you want to restore _all_ C source files to match the version in
132 +the index, you can say
133 +
134 +------------
135 +$ git restore '*.c'
136 +------------
137 +
138 +Note the quotes around `*.c`. The file `hello.c` will also be
139 +restored, even though it is no longer in the working tree, because the
140 +file globbing is used to match entries in the index (not in the
141 +working tree by the shell).
142 +
143 +To restore all files in the current directory
144 +
145 +------------
146 +$ git restore .
147 +------------
148 +
149 +or to restore all working tree files with 'top' pathspec magic (see
150 +linkgit:gitglossary[7])
151 +
152 +------------
153 +$ git restore :/
154 +------------
155 +
156 +To restore a file in the index to match the version in `HEAD` (this is
157 +the same as using linkgit:git-reset[1])
158 +
159 +------------
160 +$ git restore --staged hello.c
161 +------------
162 +
163 +or you can restore both the index and the working tree (this the same
164 +as using linkgit:git-checkout[1])
165 +
166 +------------
167 +$ git restore --source=HEAD --staged --worktree hello.c
168 +------------
169 +
170 +or the short form which is more practical but less readable:
171 +
172 +------------
173 +$ git restore -s@ -SW hello.c
174 +------------
175 +
176 +SEE ALSO
177 +--------
178 +linkgit:git-checkout[1],
179 +linkgit:git-reset[1]
180 +
181 +GIT
182 +---
183 +Part of the linkgit:git[1] suite
Documentation/git-revert.txt
+3
@@ -30,6 +30,9 @@ should see linkgit:git-checkout[1], specifically the `git checkout
30 <commit> -- <filename>` syntax. Take care with these alternatives as
31 both will discard uncommitted changes in your working directory.
32
33 +See "Reset, restore and revert" in linkgit:git[1] for the differences
34 +between the three commands.
35 +
36 OPTIONS
37 -------
38 <commit>...::
Documentation/git.txt
+20
@@ -210,6 +210,26 @@ people via patch over e-mail.
210
211 include::cmds-foreignscminterface.txt[]
212
213 +Reset, restore and revert
214 +~~~~~~~~~~~~~~~~~~~~~~~~~
215 +There are three commands with similar names: `git reset`,
216 +`git restore` and `git revert`.
217 +
218 +* linkgit:git-revert[1] is about making a new commit that reverts the
219 + changes made by other commits.
220 +
221 +* linkgit:git-restore[1] is about restoring files in the working tree
222 + from either the index or another commit. This command does not
223 + update your branch. The command can also be used to restore files in
224 + the index from another commit.
225 +
226 +* linkgit:git-reset[1] is about updating your branch, moving the tip
227 + in order to add or remove commits from the branch. This operation
228 + changes the commit history.
229 ++
230 +`git reset` can also be used to restore the index, overlapping with
231 +`git restore`.
232 +
233
234 Low-level commands (plumbing)
235 -----------------------------
Documentation/gitcli.txt
+12
@@ -209,6 +209,18 @@ See also http://marc.info/?l=git&m=116563135620359 and
209 http://marc.info/?l=git&m=119150393620273 for further
210 information.
211
212 +Some other commands that also work on files in the working tree and/or
213 +in the index can take `--staged` and/or `--worktree`.
214 +
215 +* `--staged` is exactly like `--cached`, which is used to ask a
216 + command to only work on the index, not the working tree.
217 +
218 +* `--worktree` is the opposite, to ask a command to work on the
219 + working tree only, not the index.
220 +
221 +* The two options can be specified together to ask a command to work
222 + on both the index and the working tree.
223 +
224 GIT
225 ---
226 Part of the linkgit:git[1] suite
Makefile
+1
@@ -799,6 +799,7 @@ BUILT_INS += git-format-patch$X
799 BUILT_INS += git-fsck-objects$X
800 BUILT_INS += git-init$X
801 BUILT_INS += git-merge-subtree$X
802 +BUILT_INS += git-restore$X
803 BUILT_INS += git-show$X
804 BUILT_INS += git-stage$X
805 BUILT_INS += git-status$X
builtin.h
+1
@@ -214,6 +214,7 @@ extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);
214 extern int cmd_repack(int argc, const char **argv, const char *prefix);
215 extern int cmd_rerere(int argc, const char **argv, const char *prefix);
216 extern int cmd_reset(int argc, const char **argv, const char *prefix);
217 +extern int cmd_restore(int argc, const char **argv, const char *prefix);
218 extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
219 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
220 extern int cmd_revert(int argc, const char **argv, const char *prefix);
builtin/checkout.c
+26
@@ -38,6 +38,11 @@ static const char * const switch_branch_usage[] = {
38 NULL,
39 };
40
41 +static const char * const restore_usage[] = {
42 + N_("git restore [<options>] [<branch>] -- <file>..."),
43 + NULL,
44 +};
45 +
46 struct checkout_opts {
47 int patch_mode;
48 int quiet;
@@ -1622,3 +1627,24 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
1627 FREE_AND_NULL(options);
1628 return ret;
1629 }
1630 +
1631 +int cmd_restore(int argc, const char **argv, const char *prefix)
1632 +{
1633 + struct checkout_opts opts;
1634 + struct option *options = NULL;
1635 + int ret;
1636 +
1637 + memset(&opts, 0, sizeof(opts));
1638 + opts.dwim_new_local_branch = 1;
1639 + opts.switch_branch_doing_nothing_is_ok = 0;
1640 + opts.accept_pathspec = 1;
1641 +
1642 + options = parse_options_dup(options);
1643 + options = add_common_options(&opts, options);
1644 + options = add_checkout_path_options(&opts, options);
1645 +
1646 + ret = checkout_main(argc, argv, prefix, &opts,
1647 + options, restore_usage);
1648 + FREE_AND_NULL(options);
1649 + return ret;
1650 +}
command-list.txt
+1
@@ -151,6 +151,7 @@ git-replace ancillarymanipulators complete
151 git-request-pull foreignscminterface complete
152 git-rerere ancillaryinterrogators
153 git-reset mainporcelain worktree
154 +git-restore mainporcelain worktree
155 git-revert mainporcelain
156 git-rev-list plumbinginterrogators
157 git-rev-parse plumbinginterrogators
git.c
+1
@@ -558,6 +558,7 @@ static struct cmd_struct commands[] = {
558 { "replace", cmd_replace, RUN_SETUP },
559 { "rerere", cmd_rerere, RUN_SETUP },
560 { "reset", cmd_reset, RUN_SETUP },
561 + { "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
562 { "rev-list", cmd_rev_list, RUN_SETUP | NO_PARSEOPT },
563 { "rev-parse", cmd_rev_parse, NO_PARSEOPT },
564 { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },