This series adds a new command "switch" for switching branches, an alternative for "git checkout". v2 fixes the comments I got from v1. I think the range-diff below summarizes it better than I do. No major changes though. Range-diff dựa trên v1: 1: 6d550b443c ! 1: 2283204090 checkout: split part of it to new command switch @@ -148,24 +148,33 @@ +-------- +[verse] +'git switch' [<options>] [--guess] <branch> -+'git switch' [<options>] --detach [<start_point>>] -+'git switch' [<options>] [[-c|-C|--orphan] <new_branch>] [<start_point>] ++'git switch' [<options>] --detach [<start-point>] ++'git switch' [<options>] (-c|-C|--orphan) <new-branch> [<start-point>] + +DESCRIPTION +----------- -+Switch to a specified branch and update files in the working tree to -+match it. Optionally a new branch could be created with either `-c` or -+`-C`, or detach from any branch with `--detach`, along with switching. ++Switch to a specified branch. The working tree and the index are ++updated to match the branch. All new commits will be added to the tip ++of this branch. ++ ++Optionally a new branch could be created with either `-c` or `-C`, or ++detach the working tree from any branch with `--detach`, along with ++switching. ++ ++Switching branches does not require a clean index and working tree ++(i.e. no differences compared to 'HEAD'). The operation is aborted ++however if the switch leads to loss of local changes, unless told ++otherwise. + +OPTIONS +------- +<branch>:: + Branch to switch to. + -+<new_branch>:: ++<new-branch>:: + Name for the new branch. + -+<start_point>:: ++<start-point>:: + The name of a commit at which to switch to before creating a + new branch or detach from. ++ @@ -177,17 +186,27 @@ +base of `A` and `B` if there is exactly one merge base. You can leave +out at most one of `A` and `B`, in which case it defaults to `HEAD`. + -+-c <new_branch>:: -+--create <new_branch>:: -+ Create a new branch named <new_branch> and start it at -+ <start_point>; see linkgit:git-branch[1] for details. ++-c <new-branch>:: ++--create <new-branch>:: ++ Create a new branch named <new-branch> starting at ++ <start-point> before switching to the branch. This is a ++ convenient shortcut for: +++ ++------------ ++$ git branch <new-branch> ++$ git switch <new-branch> ++------------ + -+-C <new_branch>:: -+--force-create <new_branch>:: -+ Creates the branch <new_branch> and start it at <start_point>; -+ if it already exists, then reset it to <start_point>. This is -+ equivalent to running "git branch" with "-f"; see -+ linkgit:git-branch[1] for details. ++-C <new-branch>:: ++--force-create <new-branch>:: ++ Similar to `--create` except that if <new-branch> already ++ exists, it will be reset to <start-point>. This is a ++ convenient shortcut for: +++ ++------------ ++$ git branch -f <new-branch> ++$ git switch <new-branch> ++------------ + +-d:: +--detach:: @@ -220,7 +239,9 @@ +-f:: +--force:: + Proceed even if the index or the working tree differs from -+ HEAD. This is used to throw away local changes. ++ HEAD. Both the index and working tree are restored to match ++ the switching target. This is used to throw away local ++ changes. + +--[no-]progress:: + Progress status is reported on the standard error stream @@ -270,9 +291,9 @@ + "merge" (default) and "diff3" (in addition to what is shown by + "merge" style, shows the original contents). + -+--orphan <new_branch>:: -+ Create a new 'orphan' branch, named <new_branch>, started from -+ <start_point> and switch to it. See explanation of the same ++--orphan <new-branch>:: ++ Create a new 'orphan' branch, named <new-branch>, started from ++ <start-point> and switch to it. See explanation of the same + option in linkgit:git-checkout[1] for details. + +--ignore-other-worktrees:: 2: e2f94df471 ! 2: deceb221dc switch: better names for -b and -B @@ -61,7 +61,7 @@ + OPT_STRING('c', "create", &opts.new_branch, N_("branch"), + N_("create and switch to a new branch")), + OPT_STRING('C', "force-create", &opts.new_branch_force, N_("branch"), -+ N_("create/reset and switch to a new branch")), ++ N_("create/reset and switch to a branch")), + OPT_END() + }; int ret; 3: b3d431a97f = 3: 08f28e9726 switch: remove -l 4: 26738818fa = 4: 9ee4852c8b switch: stop accepting pathspec 5: 79ebe7a68c ! 5: 0a7ea4b33b switch: reject "do nothing" case @@ -32,7 +32,7 @@ + !new_branch_info->name && + !opts->new_branch && + !opts->force_detach) -+ die(_("nothing to do")); ++ die(_("missing branch or commit argument")); + if (new_branch_info->path && !opts->force_detach && !opts->new_branch && !opts->ignore_other_worktrees) { 6: bc36ac8510 ! 6: eedf82c72b switch: only allow explicit detached HEAD @@ -26,7 +26,7 @@ int ignore_skipworktree; @@ !opts->force_detach) - die(_("nothing to do")); + die(_("missing branch or commit argument")); + if (!opts->implicit_detach && + !opts->force_detach && 7: 1a761ce8e5 = 7: 9314ff16c9 switch: add short option for --detach 8: 738c560eb9 ! 8: 9d8e461df2 switch: no implicit dwim, use --guess to dwim @@ -143,7 +143,7 @@ @@ N_("create and switch to a new branch")), OPT_STRING('C', "force-create", &opts.new_branch_force, N_("branch"), - N_("create/reset and switch to a new branch")), + N_("create/reset and switch to a branch")), + OPT_BOOL('g', "guess", &opts.dwim_new_local_branch, + N_("second guess 'git switch <no-such-branch>'")), OPT_END() 9: 456e9340f1 = 9: 749665c457 switch: no worktree status unless real branch switch happens 10: cdd132a7e2 ! 10: e4e0b397eb t: add tests for switch @@ -51,9 +51,7 @@ +test_expect_success 'switch and create branch' ' + test_when_finished git switch master && + git switch -c temp master^ && -+ git rev-parse master^ >expected && -+ git rev-parse refs/heads/temp >actual && -+ test_cmp expected actual && ++ test_cmp_rev master^ refs/heads/temp && + echo refs/heads/temp >expected-branch && + git symbolic-ref HEAD >actual-branch && + test_cmp expected-branch actual-branch @@ -63,9 +61,7 @@ + test_when_finished git switch master && + git switch --detach master && + git switch -C temp && -+ git rev-parse master >expected && -+ git rev-parse refs/heads/temp >actual && -+ test_cmp expected actual && ++ test_cmp_rev master refs/heads/temp && + echo refs/heads/temp >expected-branch && + git symbolic-ref HEAD >actual-branch && + test_cmp expected-branch actual-branch 11: 96a97fcab4 = 11: b9a7662271 completion: support switch 12: 8d984bc684 ! 12: 7449a0c4cc doc: promote "git switch" @@ -40,14 +40,18 @@ + <1> This step and the next one could be combined into a single step with @@ + NOTES ----- - If you are creating a branch that you want to checkout immediately, it is +-If you are creating a branch that you want to checkout immediately, it is -easier to use the git checkout command with its `-b` option to create -+easier to use the "git switch" command with its `-c` option to create - a branch and check it out with a single command. +-a branch and check it out with a single command. ++If you are creating a branch that you want to switch to immediately, ++it is easier to use the "git switch" command with its `-c` option to ++do the same thing with a single command. The options `--contains`, `--no-contains`, `--merged` and `--no-merged` + serve four related but different purposes: diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt --- a/Documentation/git-check-ref-format.txt @@ -473,9 +477,11 @@ ------------------------------------------------------ -The `git checkout` command normally expects a branch head, but will also +-accept an arbitrary commit; for example, you can check out the commit +-referenced by a tag: +The `git switch` command normally expects a branch head, but will also - accept an arbitrary commit; for example, you can check out the commit - referenced by a tag: ++accept an arbitrary commit when invoked with --detach; for example, ++you can check out the commit referenced by a tag: ------------------------------------------------ -$ git checkout v2.6.17 @@ -628,36 +634,23 @@ { const char *fmt = - _("Note: checking out '%s'.\n\n" -+ _("Note: checking out '%s'.\n" ++ _("Note: switching to '%s'.\n" + "\n" "You are in 'detached HEAD' state. You can look around, make experimental\n" "changes and commit them, and you can discard any commits you make in this\n" - "state without impacting any branches by performing another checkout.\n\n" -+ "state without impacting any branches by performing another checkout.\n" ++ "state without impacting any branches by switching back to a branch.\n" + "\n" "If you want to create a new branch to retain commits you create, you may\n" - "do so (now or later) by using -b with the checkout command again. Example:\n\n" - " git checkout -b <new-branch-name>\n\n"); -+ "do so (now or later) by using -b with the checkout command again. Example:\n" ++ "do so (now or later) by using -c with the switch command. Example:\n" + "\n" + " git switch -c <new-branch-name>\n\n"); fprintf(stderr, fmt, new_name); } - diff --git a/builtin/clone.c b/builtin/clone.c - --- a/builtin/clone.c - +++ b/builtin/clone.c -@@ - static const char junk_leave_repo_msg[] = - N_("Clone succeeded, but checkout failed.\n" - "You can inspect what was checked out with 'git status'\n" -- "and retry the checkout with 'git checkout -f HEAD'\n"); -+ "and retry the checkout with 'git switch -f HEAD'\n"); - - static void remove_junk(void) - { - diff --git a/sha1-name.c b/sha1-name.c --- a/sha1-name.c +++ b/sha1-name.c @@ -675,8 +668,20 @@ --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ + + # The first detach operation is more chatty than the following ones. + cat >1st_detach <<-EOF && +- Note: checking out 'HEAD^'. ++ Note: switching to 'HEAD^'. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this +- state without impacting any branches by performing another checkout. ++ state without impacting any branches by switching back to a branch. + If you want to create a new branch to retain commits you create, you may - do so (now or later) by using -b with the checkout command again. Example: +- do so (now or later) by using -b with the checkout command again. Example: ++ do so (now or later) by using -c with the switch command. Example: - git checkout -b <new-branch-name> + git switch -c <new-branch-name> @@ -684,8 +689,20 @@ HEAD is now at \$commit three EOF @@ + + # The first detach operation is more chatty than the following ones. + cat >1st_detach <<-EOF && +- Note: checking out 'HEAD^'. ++ Note: switching to 'HEAD^'. + + You are in 'detached HEAD' state. You can look around, make experimental + changes and commit them, and you can discard any commits you make in this +- state without impacting any branches by performing another checkout. ++ state without impacting any branches by switching back to a branch. + If you want to create a new branch to retain commits you create, you may - do so (now or later) by using -b with the checkout command again. Example: +- do so (now or later) by using -b with the checkout command again. Example: ++ do so (now or later) by using -c with the switch command. Example: - git checkout -b <new-branch-name> + git switch -c <new-branch-name> 13: 91e5442069 < -: ---------- checkout: split part of it to new command restore 14: 6bc8f87c0a < -: ---------- restore: take tree-ish from --from option instead 15: 095a1cd3e3 < -: ---------- restore: make pathspec mandatory 16: 6eb5612187 < -: ---------- restore: disable overlay mode by default 17: cc79522047 < -: ---------- t: add tests for restore 18: ed5d7097b6 < -: ---------- completion: support restore 19: 625a4fac68 < -: ---------- doc: promote "git restore" Nguyễn Thái Ngọc Duy (19): git-checkout.txt: fix one syntax line doc: document --overwrite-ignore t: rename t2014-switch.sh to t2014-checkout-switch.sh checkout: factor out some code in parse_branchname_arg() checkout: make "opts" in cmd_checkout() a pointer checkout: move 'confict_style' and 'dwim_..' to checkout_opts checkout: split options[] array in three pieces checkout: split part of it to new command switch switch: better names for -b and -B switch: remove -l switch: stop accepting pathspec switch: reject "do nothing" case switch: only allow explicit detached HEAD switch: add short option for --detach switch: no implicit dwim, use --guess to dwim switch: no worktree status unless real branch switch happens t: add tests for switch completion: support switch doc: promote "git switch" .gitignore | 1 + Documentation/config/advice.txt | 13 +- Documentation/config/branch.txt | 4 +- Documentation/config/checkout.txt | 17 +- Documentation/config/diff.txt | 3 +- Documentation/git-branch.txt | 12 +- Documentation/git-check-ref-format.txt | 3 +- Documentation/git-checkout.txt | 48 +- Documentation/git-format-patch.txt | 2 +- Documentation/git-merge-base.txt | 2 +- Documentation/git-merge.txt | 4 + Documentation/git-rebase.txt | 2 +- Documentation/git-remote.txt | 2 +- Documentation/git-rerere.txt | 10 +- Documentation/git-reset.txt | 20 +- Documentation/git-stash.txt | 9 +- Documentation/git-switch.txt | 257 ++++++++++ Documentation/gitattributes.txt | 3 +- Documentation/gitcore-tutorial.txt | 18 +- Documentation/giteveryday.txt | 24 +- Documentation/githooks.txt | 8 +- Documentation/gittutorial.txt | 4 +- Documentation/revisions.txt | 2 +- Documentation/user-manual.txt | 56 +-- Makefile | 1 + advice.c | 11 +- builtin.h | 1 + builtin/checkout.c | 464 +++++++++--------- command-list.txt | 1 + contrib/completion/git-completion.bash | 26 + git.c | 1 + parse-options-cb.c | 17 + parse-options.h | 3 +- sha1-name.c | 2 +- t/t1090-sparse-checkout-scope.sh | 14 - ...014-switch.sh => t2014-checkout-switch.sh} | 0 t/t2020-checkout-detach.sh | 16 +- t/t2060-switch.sh | 87 ++++ 38 files changed, 796 insertions(+), 372 deletions(-) create mode 100644 Documentation/git-switch.txt rename t/{t2014-switch.sh => t2014-checkout-switch.sh} (100%) create mode 100755 t/t2060-switch.sh -- 2.20.1.682.gd5861c6d90