diff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt index d6872ffa83ea5a..6b646813abadc9 100644 --- a/Documentation/config/checkout.txt +++ b/Documentation/config/checkout.txt @@ -16,11 +16,3 @@ will checkout the '' branch on another remote, and by linkgit:git-worktree[1] when 'git worktree add' refers to a remote branch. This setting might be used for other checkout-like commands or functionality in the future. - -checkout.optimizeNewBranch:: - Optimizes the performance of "git checkout -b " when - using sparse-checkout. When set to true, git will not update the - repo based on the current sparse-checkout settings. This means it - will not update the skip-worktree bit in the index nor add/remove - files in the working directory to reflect the current sparse checkout - settings nor will it show the local changes. diff --git a/builtin/checkout.c b/builtin/checkout.c index d908d2dcb6c257..8a7f375b1213ba 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -28,8 +28,6 @@ #include "xdiff-interface.h" #include "packfile.h" -static int checkout_optimize_new_branch; - static const char * const checkout_usage[] = { N_("git checkout [] "), N_("git checkout [] [] -- ..."), @@ -74,11 +72,6 @@ struct checkout_opts { const char *ignore_unmerged_opt; int ignore_unmerged; - /* - * If new checkout options are added, skip_merge_working_tree - * should be updated accordingly. - */ - const char *new_branch; const char *new_branch_force; const char *new_orphan_branch; @@ -647,112 +640,6 @@ static void setup_branch_path(struct branch_info *branch) branch->path = strbuf_detach(&buf, NULL); } -/* - * Skip merging the trees, updating the index and working directory if and - * only if we are creating a new branch via "git checkout -b ." - */ -static int skip_merge_working_tree(const struct checkout_opts *opts, - const struct branch_info *old_branch_info, - const struct branch_info *new_branch_info) -{ - /* - * Do the merge if sparse checkout is on and the user has not opted in - * to the optimized behavior - */ - if (core_sparse_checkout && !checkout_optimize_new_branch) - return 0; - - /* - * We must do the merge if we are actually moving to a new commit. - */ - if (!old_branch_info->commit || !new_branch_info->commit || - !oideq(&old_branch_info->commit->object.oid, - &new_branch_info->commit->object.oid)) - return 0; - - /* - * opts->patch_mode cannot be used with switching branches so is - * not tested here - */ - - /* - * opts->quiet only impacts output so doesn't require a merge - */ - - /* - * Honor the explicit request for a three-way merge or to throw away - * local changes - */ - if (opts->merge || opts->force) - return 0; - - /* - * --detach is documented as "updating the index and the files in the - * working tree" but this optimization skips those steps so fall through - * to the regular code path. - */ - if (opts->force_detach) - return 0; - - /* - * opts->writeout_stage cannot be used with switching branches so is - * not tested here - */ - - /* - * Honor the explicit ignore requests - */ - if (!opts->overwrite_ignore || opts->ignore_skipworktree || - opts->ignore_other_worktrees) - return 0; - - /* - * opts->show_progress only impacts output so doesn't require a merge - */ - - /* - * opts->overlay_mode cannot be used with switching branches so is - * not tested here - */ - - /* - * If we aren't creating a new branch any changes or updates will - * happen in the existing branch. Since that could only be updating - * the index and working directory, we don't want to skip those steps - * or we've defeated any purpose in running the command. - */ - if (!opts->new_branch) - return 0; - - /* - * new_branch_force is defined to "create/reset and checkout a branch" - * so needs to go through the merge to do the reset - */ - if (opts->new_branch_force) - return 0; - - /* - * A new orphaned branch requrires the index and the working tree to be - * adjusted to - */ - if (opts->new_orphan_branch) - return 0; - - /* - * Remaining variables are not checkout options but used to track state - */ - - /* - * Do the merge if this is the initial checkout. We cannot use - * is_cache_unborn() here because the index hasn't been loaded yet - * so cache_nr and timestamp.sec are always zero. - */ - if (!file_exists(get_index_file())) - return 0; - - return 1; -} - static int merge_working_tree(const struct checkout_opts *opts, struct branch_info *old_branch_info, struct branch_info *new_branch_info, @@ -1163,6 +1050,7 @@ static int switch_branches(const struct checkout_opts *opts, BUG("'switch --orphan' should never accept a commit as starting point"); new_branch_info->commit = NULL; new_branch_info->name = "(empty)"; + do_merge = 1; } if (!new_branch_info->name) { @@ -1176,16 +1064,7 @@ static int switch_branches(const struct checkout_opts *opts, do_merge = 0; } - /* optimize the "checkout -b path */ - if (!do_merge || skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) { - if (!checkout_optimize_new_branch && !opts->quiet) { - if (read_cache_preload(NULL) < 0) - return error(_("index file corrupt")); - show_local_changes(&new_branch_info->commit->object, &opts->diff_options); - } - if (!opts->only_merge_on_switching_branches) - warning(_("'git checkout -b ' is being deprecated in favor of 'git switch -c '. Please adjust your workflow accordingly.")); - } else { + if (do_merge) { ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error); if (ret) { free(path_to_free); @@ -1205,11 +1084,6 @@ static int switch_branches(const struct checkout_opts *opts, static int git_checkout_config(const char *var, const char *value, void *cb) { - if (!strcmp(var, "checkout.optimizenewbranch")) { - checkout_optimize_new_branch = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "diff.ignoresubmodules")) { struct checkout_opts *opts = cb; handle_ignore_submodules_arg(&opts->diff_options, value); @@ -1851,6 +1725,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.checkout_index = -2; /* default on */ opts.checkout_worktree = -2; /* default on */ + if (argc == 3 && !strcmp(argv[1], "-b")) { + /* + * User ran 'git checkout -b ' and expects + * the same behavior as 'git switch -c '. + */ + opts.switch_branch_doing_nothing_is_ok = 0; + opts.only_merge_on_switching_branches = 1; + } + options = parse_options_dup(checkout_options); options = add_common_options(&opts, options); options = add_common_switch_branch_options(&opts, options); diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh index 62735a6113c980..ac786c7e7af010 100755 --- a/t/t1090-sparse-checkout-scope.sh +++ b/t/t1090-sparse-checkout-scope.sh @@ -31,20 +31,6 @@ test_expect_success 'perform sparse checkout of master' ' test_path_is_file c ' -test_expect_success 'checkout -b checkout.optimizeNewBranch interaction' ' - cp .git/info/sparse-checkout .git/info/sparse-checkout.bak && - test_when_finished " - mv -f .git/info/sparse-checkout.bak .git/info/sparse-checkout - git checkout master - " && - echo "/b" >>.git/info/sparse-checkout && - test "$(git ls-files -t b)" = "S b" && - git -c checkout.optimizeNewBranch=true checkout -b fast && - test "$(git ls-files -t b)" = "S b" && - git checkout -b slow && - test "$(git ls-files -t b)" = "H b" -' - test_expect_success 'merge feature branch into sparse checkout of master' ' git merge feature && test_path_is_file a && diff --git a/t/t7114-reset-sparse-checkout.sh b/t/t7114-reset-sparse-checkout.sh index 8dd88fd46d3938..c46cbdb64e4ebc 100755 --- a/t/t7114-reset-sparse-checkout.sh +++ b/t/t7114-reset-sparse-checkout.sh @@ -24,7 +24,7 @@ test_expect_success 'setup' ' test_expect_success 'reset when there is a sparse-checkout' ' echo "/c" >.git/info/sparse-checkout && test_config core.sparsecheckout true && - git checkout -b resetBranch && + git checkout -B resetBranch && test_path_is_missing m && test_path_is_missing a && test_path_is_missing d && @@ -41,7 +41,7 @@ test_expect_success 'reset after deleting file without skip-worktree bit' ' echo "/c /m" >.git/info/sparse-checkout && test_config core.sparsecheckout true && - git checkout -b resetAfterDelete && + git checkout -B resetAfterDelete && test_path_is_file m && test_path_is_missing a && test_path_is_missing d &&