Skip to content

Commit f7ba8e3

Browse files
Merge pull request git-for-windows#193: Update to include 'checkout -b' fix
In git-for-windows#183, we quickly fixed a performance problem around `git checkout -b` and added a deprecation waning. After submitting that upstream, we found instead the commit 3136776, which just puts a simple performance hack in to `git checkout` to check for exactly `checkout -b <branch>` and then use the `git switch -c <branch>` logic. This PR reverts the commits from git-for-windows#183 as fixups and merges in the commit from upstream instead.
2 parents 2c98bc7 + 6aab73e commit f7ba8e3

File tree

4 files changed

+13
-152
lines changed

4 files changed

+13
-152
lines changed

Documentation/config/checkout.txt

-8
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,3 @@ will checkout the '<something>' branch on another remote,
1616
and by linkgit:git-worktree[1] when 'git worktree add' refers to a
1717
remote branch. This setting might be used for other checkout-like
1818
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

+11-128
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
#include "xdiff-interface.h"
2929
#include "packfile.h"
3030

31-
static int checkout_optimize_new_branch;
32-
3331
static const char * const checkout_usage[] = {
3432
N_("git checkout [<options>] <branch>"),
3533
N_("git checkout [<options>] [<branch>] -- <file>..."),
@@ -74,11 +72,6 @@ struct checkout_opts {
7472
const char *ignore_unmerged_opt;
7573
int ignore_unmerged;
7674

77-
/*
78-
* If new checkout options are added, skip_merge_working_tree
79-
* should be updated accordingly.
80-
*/
81-
8275
const char *new_branch;
8376
const char *new_branch_force;
8477
const char *new_orphan_branch;
@@ -647,112 +640,6 @@ static void setup_branch_path(struct branch_info *branch)
647640
branch->path = strbuf_detach(&buf, NULL);
648641
}
649642

650-
/*
651-
* Skip merging the trees, updating the index and working directory if and
652-
* only if we are creating a new branch via "git checkout -b <new_branch>."
653-
*/
654-
static int skip_merge_working_tree(const struct checkout_opts *opts,
655-
const struct branch_info *old_branch_info,
656-
const struct branch_info *new_branch_info)
657-
{
658-
/*
659-
* Do the merge if sparse checkout is on and the user has not opted in
660-
* to the optimized behavior
661-
*/
662-
if (core_sparse_checkout && !checkout_optimize_new_branch)
663-
return 0;
664-
665-
/*
666-
* We must do the merge if we are actually moving to a new commit.
667-
*/
668-
if (!old_branch_info->commit || !new_branch_info->commit ||
669-
!oideq(&old_branch_info->commit->object.oid,
670-
&new_branch_info->commit->object.oid))
671-
return 0;
672-
673-
/*
674-
* opts->patch_mode cannot be used with switching branches so is
675-
* not tested here
676-
*/
677-
678-
/*
679-
* opts->quiet only impacts output so doesn't require a merge
680-
*/
681-
682-
/*
683-
* Honor the explicit request for a three-way merge or to throw away
684-
* local changes
685-
*/
686-
if (opts->merge || opts->force)
687-
return 0;
688-
689-
/*
690-
* --detach is documented as "updating the index and the files in the
691-
* working tree" but this optimization skips those steps so fall through
692-
* to the regular code path.
693-
*/
694-
if (opts->force_detach)
695-
return 0;
696-
697-
/*
698-
* opts->writeout_stage cannot be used with switching branches so is
699-
* not tested here
700-
*/
701-
702-
/*
703-
* Honor the explicit ignore requests
704-
*/
705-
if (!opts->overwrite_ignore || opts->ignore_skipworktree ||
706-
opts->ignore_other_worktrees)
707-
return 0;
708-
709-
/*
710-
* opts->show_progress only impacts output so doesn't require a merge
711-
*/
712-
713-
/*
714-
* opts->overlay_mode cannot be used with switching branches so is
715-
* not tested here
716-
*/
717-
718-
/*
719-
* If we aren't creating a new branch any changes or updates will
720-
* happen in the existing branch. Since that could only be updating
721-
* the index and working directory, we don't want to skip those steps
722-
* or we've defeated any purpose in running the command.
723-
*/
724-
if (!opts->new_branch)
725-
return 0;
726-
727-
/*
728-
* new_branch_force is defined to "create/reset and checkout a branch"
729-
* so needs to go through the merge to do the reset
730-
*/
731-
if (opts->new_branch_force)
732-
return 0;
733-
734-
/*
735-
* A new orphaned branch requrires the index and the working tree to be
736-
* adjusted to <start_point>
737-
*/
738-
if (opts->new_orphan_branch)
739-
return 0;
740-
741-
/*
742-
* Remaining variables are not checkout options but used to track state
743-
*/
744-
745-
/*
746-
* Do the merge if this is the initial checkout. We cannot use
747-
* is_cache_unborn() here because the index hasn't been loaded yet
748-
* so cache_nr and timestamp.sec are always zero.
749-
*/
750-
if (!file_exists(get_index_file()))
751-
return 0;
752-
753-
return 1;
754-
}
755-
756643
static int merge_working_tree(const struct checkout_opts *opts,
757644
struct branch_info *old_branch_info,
758645
struct branch_info *new_branch_info,
@@ -1163,6 +1050,7 @@ static int switch_branches(const struct checkout_opts *opts,
11631050
BUG("'switch --orphan' should never accept a commit as starting point");
11641051
new_branch_info->commit = NULL;
11651052
new_branch_info->name = "(empty)";
1053+
do_merge = 1;
11661054
}
11671055

11681056
if (!new_branch_info->name) {
@@ -1176,16 +1064,7 @@ static int switch_branches(const struct checkout_opts *opts,
11761064
do_merge = 0;
11771065
}
11781066

1179-
/* optimize the "checkout -b <new_branch> path */
1180-
if (!do_merge || skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) {
1181-
if (!checkout_optimize_new_branch && !opts->quiet) {
1182-
if (read_cache_preload(NULL) < 0)
1183-
return error(_("index file corrupt"));
1184-
show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
1185-
}
1186-
if (!opts->only_merge_on_switching_branches)
1187-
warning(_("'git checkout -b <new-branch>' is being deprecated in favor of 'git switch -c <new-branch>'. Please adjust your workflow accordingly."));
1188-
} else {
1067+
if (do_merge) {
11891068
ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
11901069
if (ret) {
11911070
free(path_to_free);
@@ -1205,11 +1084,6 @@ static int switch_branches(const struct checkout_opts *opts,
12051084

12061085
static int git_checkout_config(const char *var, const char *value, void *cb)
12071086
{
1208-
if (!strcmp(var, "checkout.optimizenewbranch")) {
1209-
checkout_optimize_new_branch = git_config_bool(var, value);
1210-
return 0;
1211-
}
1212-
12131087
if (!strcmp(var, "diff.ignoresubmodules")) {
12141088
struct checkout_opts *opts = cb;
12151089
handle_ignore_submodules_arg(&opts->diff_options, value);
@@ -1851,6 +1725,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
18511725
opts.checkout_index = -2; /* default on */
18521726
opts.checkout_worktree = -2; /* default on */
18531727

1728+
if (argc == 3 && !strcmp(argv[1], "-b")) {
1729+
/*
1730+
* User ran 'git checkout -b <branch>' and expects
1731+
* the same behavior as 'git switch -c <branch>'.
1732+
*/
1733+
opts.switch_branch_doing_nothing_is_ok = 0;
1734+
opts.only_merge_on_switching_branches = 1;
1735+
}
1736+
18541737
options = parse_options_dup(checkout_options);
18551738
options = add_common_options(&opts, options);
18561739
options = add_common_switch_branch_options(&opts, options);

t/t1090-sparse-checkout-scope.sh

-14
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,6 @@ test_expect_success 'perform sparse checkout of master' '
3131
test_path_is_file c
3232
'
3333

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-
4834
test_expect_success 'merge feature branch into sparse checkout of master' '
4935
git merge feature &&
5036
test_path_is_file a &&

t/t7114-reset-sparse-checkout.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ test_expect_success 'setup' '
2424
test_expect_success 'reset when there is a sparse-checkout' '
2525
echo "/c" >.git/info/sparse-checkout &&
2626
test_config core.sparsecheckout true &&
27-
git checkout -b resetBranch &&
27+
git checkout -B resetBranch &&
2828
test_path_is_missing m &&
2929
test_path_is_missing a &&
3030
test_path_is_missing d &&
@@ -41,7 +41,7 @@ test_expect_success 'reset after deleting file without skip-worktree bit' '
4141
echo "/c
4242
/m" >.git/info/sparse-checkout &&
4343
test_config core.sparsecheckout true &&
44-
git checkout -b resetAfterDelete &&
44+
git checkout -B resetAfterDelete &&
4545
test_path_is_file m &&
4646
test_path_is_missing a &&
4747
test_path_is_missing d &&

0 commit comments

Comments
 (0)