restore: take tree-ish from --source option instead

This is another departure from 'git checkout' syntax, which uses -- to separate ref and pathspec. The observation is restore (or "git checkout -- <pathspec>") is most often used to restore some files from the index. If this is correct, we can simplify it by taking away the ref, so that we can write git restore some-file without worrying about some-file being a ref and whether we need to do git restore -- some-file for safety. If the source of the restore comes from a tree, it will be in the form of an option with value, e.g. git restore --source=this-tree some-file This is of course longer to type than using "--". But hopefully it will not be used as often, and it is clearly easier to understand. dwim_new_local_branch is no longer set (or unset) in cmd_restore_files() because it's irrelevant because we don't really care about dwim-ing. With accept_ref being unset, dwim can't happen. 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 c9c935f6d4519c53f27f50113bea2c17deb8b71e
1 file changed +34 -8
builtin/checkout.c
+34 -8
@@ -39,7 +39,7 @@ static const char * const switch_branch_usage[] = {
39 };
40
41 static const char * const restore_usage[] = {
42 - N_("git restore [<options>] [<branch>] -- <file>..."),
42 + N_("git restore [<options>] [--source=<branch>] <file>..."),
43 NULL,
44 };
45
@@ -59,6 +59,7 @@ struct checkout_opts {
59 int overlay_mode;
60 int dwim_new_local_branch;
61 int discard_changes;
62 + int accept_ref;
63 int accept_pathspec;
64 int switch_branch_doing_nothing_is_ok;
65 int only_merge_on_switching_branches;
@@ -76,6 +77,7 @@ struct checkout_opts {
77 int branch_exists;
78 const char *prefix;
79 struct pathspec pathspec;
80 + const char *from_treeish;
81 struct tree *source_tree;
82 };
83
@@ -1410,6 +1412,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
1412 {
1413 struct branch_info new_branch_info;
1414 int dwim_remotes_matched = 0;
1415 + int parseopt_flags = 0;
1416
1417 memset(&new_branch_info, 0, sizeof(new_branch_info));
1418 opts->overwrite_ignore = 1;
@@ -1421,8 +1424,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
1424
1425 opts->track = BRANCH_TRACK_UNSPECIFIED;
1426
1424 - argc = parse_options(argc, argv, prefix, options, usagestr,
1425 - PARSE_OPT_KEEP_DASHDASH);
1427 + if (!opts->accept_pathspec && !opts->accept_ref)
1428 + BUG("make up your mind, you need to take _something_");
1429 + if (opts->accept_pathspec && opts->accept_ref)
1430 + parseopt_flags = PARSE_OPT_KEEP_DASHDASH;
1431 +
1432 + argc = parse_options(argc, argv, prefix, options,
1433 + usagestr, parseopt_flags);
1434
1435 if (opts->show_progress < 0) {
1436 if (opts->quiet)
@@ -1481,7 +1489,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
1489 * including "last branch" syntax and DWIM-ery for names of
1490 * remote branches, erroring out for invalid or ambiguous cases.
1491 */
1484 - if (argc) {
1492 + if (argc && opts->accept_ref) {
1493 struct object_id rev;
1494 int dwim_ok =
1495 !opts->patch_mode &&
@@ -1493,6 +1501,18 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
1501 &dwim_remotes_matched);
1502 argv += n;
1503 argc -= n;
1504 + } else if (!opts->accept_ref && opts->from_treeish) {
1505 + struct object_id rev;
1506 +
1507 + if (get_oid_mb(opts->from_treeish, &rev))
1508 + die(_("could not resolve %s"), opts->from_treeish);
1509 +
1510 + setup_new_branch_info_and_source_tree(&new_branch_info,
1511 + opts, &rev,
1512 + opts->from_treeish);
1513 +
1514 + if (!opts->source_tree)
1515 + die(_("reference is not a tree: %s"), opts->from_treeish);
1516 }
1517
1518 if (argc) {
@@ -1576,6 +1596,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1596 opts.dwim_new_local_branch = 1;
1597 opts.switch_branch_doing_nothing_is_ok = 1;
1598 opts.only_merge_on_switching_branches = 0;
1599 + opts.accept_ref = 1;
1600 opts.accept_pathspec = 1;
1601 opts.implicit_detach = 1;
1602 opts.can_switch_when_in_progress = 1;
@@ -1611,6 +1632,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
1632
1633 memset(&opts, 0, sizeof(opts));
1634 opts.dwim_new_local_branch = 1;
1635 + opts.accept_ref = 1;
1636 opts.accept_pathspec = 0;
1637 opts.switch_branch_doing_nothing_is_ok = 0;
1638 opts.only_merge_on_switching_branches = 1;
@@ -1631,15 +1653,19 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
1653 int cmd_restore(int argc, const char **argv, const char *prefix)
1654 {
1655 struct checkout_opts opts;
1634 - struct option *options = NULL;
1656 + struct option *options;
1657 + struct option restore_options[] = {
1658 + OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
1659 + N_("where the checkout from")),
1660 + OPT_END()
1661 + };
1662 int ret;
1663
1664 memset(&opts, 0, sizeof(opts));
1638 - opts.dwim_new_local_branch = 1;
1639 - opts.switch_branch_doing_nothing_is_ok = 0;
1665 + opts.accept_ref = 0;
1666 opts.accept_pathspec = 1;
1667
1642 - options = parse_options_dup(options);
1668 + options = parse_options_dup(restore_options);
1669 options = add_common_options(&opts, options);
1670 options = add_checkout_path_options(&opts, options);
1671