switch: no worktree status unless real branch switch happens

When we switch from one branch to another, it makes sense to show a summary of local changes since there could be conflicts, or some files left modified.... When switch is used solely for creating a new branch (and "switch" to the same commit) or detaching, we don't really need to show anything. "git checkout" does it anyway for historical reasons. But we can start with a clean slate with switch and don't have to. This essentially reverts fa655d8411 (checkout: optimize "git checkout -b <new_branch>" - 2018-08-16) and make it default for switch, but also for -B and --detach. Users of big repos are encouraged to move to switch. 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 Mar 29, 2019 at 17:39 UTC 65f099b3988198f0fdf3ef7a21dc01c556d21fff
3 files changed +8 -148
Documentation/config/checkout.txt
-8
@@ -16,11 +16,3 @@ will checkout the '<something>' branch on another remote,
16 and by linkgit:git-worktree[1] when 'git worktree add' refers to a
17 remote branch. This setting might be used for other checkout-like
18 commands or functionality in the future.
19 -
20 -checkout.optimizeNewBranch::
21 - Optimizes the performance of "git checkout -b <new_branch>" when
22 - using sparse-checkout. When set to true, git will not update the
23 - repo based on the current sparse-checkout settings. This means it
24 - will not update the skip-worktree bit in the index nor add/remove
25 - files in the working directory to reflect the current sparse checkout
26 - settings nor will it show the local changes.
builtin/checkout.c
+8 -126
@@ -26,8 +26,6 @@
26 #include "unpack-trees.h"
27 #include "xdiff-interface.h"
28
29 -static int checkout_optimize_new_branch;
30 -
29 static const char * const checkout_usage[] = {
30 N_("git checkout [<options>] <branch>"),
31 N_("git checkout [<options>] [<branch>] -- <file>..."),
@@ -57,11 +55,7 @@ struct checkout_opts {
55 int discard_changes;
56 int accept_pathspec;
57 int switch_branch_doing_nothing_is_ok;
60 -
61 - /*
62 - * If new checkout options are added, skip_merge_working_tree
63 - * should be updated accordingly.
64 - */
58 + int only_merge_on_switching_branches;
59
60 const char *new_branch;
61 const char *new_branch_force;
@@ -565,112 +559,6 @@ static void setup_branch_path(struct branch_info *branch)
559 branch->path = strbuf_detach(&buf, NULL);
560 }
561
568 -/*
569 - * Skip merging the trees, updating the index and working directory if and
570 - * only if we are creating a new branch via "git checkout -b <new_branch>."
571 - */
572 -static int skip_merge_working_tree(const struct checkout_opts *opts,
573 - const struct branch_info *old_branch_info,
574 - const struct branch_info *new_branch_info)
575 -{
576 - /*
577 - * Do the merge if sparse checkout is on and the user has not opted in
578 - * to the optimized behavior
579 - */
580 - if (core_apply_sparse_checkout && !checkout_optimize_new_branch)
581 - return 0;
582 -
583 - /*
584 - * We must do the merge if we are actually moving to a new commit.
585 - */
586 - if (!old_branch_info->commit || !new_branch_info->commit ||
587 - !oideq(&old_branch_info->commit->object.oid,
588 - &new_branch_info->commit->object.oid))
589 - return 0;
590 -
591 - /*
592 - * opts->patch_mode cannot be used with switching branches so is
593 - * not tested here
594 - */
595 -
596 - /*
597 - * opts->quiet only impacts output so doesn't require a merge
598 - */
599 -
600 - /*
601 - * Honor the explicit request for a three-way merge or to throw away
602 - * local changes
603 - */
604 - if (opts->merge || opts->force)
605 - return 0;
606 -
607 - /*
608 - * --detach is documented as "updating the index and the files in the
609 - * working tree" but this optimization skips those steps so fall through
610 - * to the regular code path.
611 - */
612 - if (opts->force_detach)
613 - return 0;
614 -
615 - /*
616 - * opts->writeout_stage cannot be used with switching branches so is
617 - * not tested here
618 - */
619 -
620 - /*
621 - * Honor the explicit ignore requests
622 - */
623 - if (!opts->overwrite_ignore || opts->ignore_skipworktree ||
624 - opts->ignore_other_worktrees)
625 - return 0;
626 -
627 - /*
628 - * opts->show_progress only impacts output so doesn't require a merge
629 - */
630 -
631 - /*
632 - * opts->overlay_mode cannot be used with switching branches so is
633 - * not tested here
634 - */
635 -
636 - /*
637 - * If we aren't creating a new branch any changes or updates will
638 - * happen in the existing branch. Since that could only be updating
639 - * the index and working directory, we don't want to skip those steps
640 - * or we've defeated any purpose in running the command.
641 - */
642 - if (!opts->new_branch)
643 - return 0;
644 -
645 - /*
646 - * new_branch_force is defined to "create/reset and checkout a branch"
647 - * so needs to go through the merge to do the reset
648 - */
649 - if (opts->new_branch_force)
650 - return 0;
651 -
652 - /*
653 - * A new orphaned branch requrires the index and the working tree to be
654 - * adjusted to <start_point>
655 - */
656 - if (opts->new_orphan_branch)
657 - return 0;
658 -
659 - /*
660 - * Remaining variables are not checkout options but used to track state
661 - */
662 -
663 - /*
664 - * Do the merge if this is the initial checkout. We cannot use
665 - * is_cache_unborn() here because the index hasn't been loaded yet
666 - * so cache_nr and timestamp.sec are always zero.
667 - */
668 - if (!file_exists(get_index_file()))
669 - return 0;
670 -
671 - return 1;
672 -}
673 -
562 static int merge_working_tree(const struct checkout_opts *opts,
563 struct branch_info *old_branch_info,
564 struct branch_info *new_branch_info,
@@ -1028,6 +916,7 @@ static int switch_branches(const struct checkout_opts *opts,
916 void *path_to_free;
917 struct object_id rev;
918 int flag, writeout_error = 0;
919 + int do_merge = 1;
920
921 trace2_cmd_mode("branch");
922
@@ -1047,16 +936,12 @@ static int switch_branches(const struct checkout_opts *opts,
936 if (!new_branch_info->commit)
937 die(_("You are on a branch yet to be born"));
938 parse_commit_or_die(new_branch_info->commit);
939 +
940 + if (opts->only_merge_on_switching_branches)
941 + do_merge = 0;
942 }
943
1052 - /* optimize the "checkout -b <new_branch> path */
1053 - if (skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) {
1054 - if (!checkout_optimize_new_branch && !opts->quiet) {
1055 - if (read_cache_preload(NULL) < 0)
1056 - return error(_("index file corrupt"));
1057 - show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
1058 - }
1059 - } else {
944 + if (do_merge) {
945 ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
946 if (ret) {
947 free(path_to_free);
@@ -1076,11 +961,6 @@ static int switch_branches(const struct checkout_opts *opts,
961
962 static int git_checkout_config(const char *var, const char *value, void *cb)
963 {
1079 - if (!strcmp(var, "checkout.optimizenewbranch")) {
1080 - checkout_optimize_new_branch = git_config_bool(var, value);
1081 - return 0;
1082 - }
1083 -
964 if (!strcmp(var, "diff.ignoresubmodules")) {
965 struct checkout_opts *opts = cb;
966 handle_ignore_submodules_arg(&opts->diff_options, value);
@@ -1631,6 +1511,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1511 memset(&opts, 0, sizeof(opts));
1512 opts.dwim_new_local_branch = 1;
1513 opts.switch_branch_doing_nothing_is_ok = 1;
1514 + opts.only_merge_on_switching_branches = 0;
1515 opts.accept_pathspec = 1;
1516 opts.implicit_detach = 1;
1517
@@ -1666,6 +1547,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
1547 opts.dwim_new_local_branch = 1;
1548 opts.accept_pathspec = 0;
1549 opts.switch_branch_doing_nothing_is_ok = 0;
1550 + opts.only_merge_on_switching_branches = 1;
1551 opts.implicit_detach = 0;
1552
1553 options = parse_options_dup(switch_options);
t/t1090-sparse-checkout-scope.sh
-14
@@ -31,20 +31,6 @@ test_expect_success 'perform sparse checkout of master' '
31 test_path_is_file c
32 '
33
34 -test_expect_success 'checkout -b checkout.optimizeNewBranch interaction' '
35 - cp .git/info/sparse-checkout .git/info/sparse-checkout.bak &&
36 - test_when_finished "
37 - mv -f .git/info/sparse-checkout.bak .git/info/sparse-checkout
38 - git checkout master
39 - " &&
40 - echo "/b" >>.git/info/sparse-checkout &&
41 - test "$(git ls-files -t b)" = "S b" &&
42 - git -c checkout.optimizeNewBranch=true checkout -b fast &&
43 - test "$(git ls-files -t b)" = "S b" &&
44 - git checkout -b slow &&
45 - test "$(git ls-files -t b)" = "H b"
46 -'
47 -
34 test_expect_success 'merge feature branch into sparse checkout of master' '
35 git merge feature &&
36 test_path_is_file a &&