|
12 | 12 | #include "strvec.h"
|
13 | 13 | #include "branch.h"
|
14 | 14 | #include "refs.h"
|
| 15 | +#include "remote.h" |
15 | 16 | #include "run-command.h"
|
16 | 17 | #include "hook.h"
|
17 | 18 | #include "sigchain.h"
|
|
40 | 41 | #define BUILTIN_WORKTREE_UNLOCK_USAGE \
|
41 | 42 | N_("git worktree unlock <worktree>")
|
42 | 43 |
|
| 44 | +#define WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT \ |
| 45 | + _("No possible source branch, inferring '--orphan'") |
| 46 | + |
43 | 47 | #define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \
|
44 | 48 | _("If you meant to create a worktree containing a new orphan branch\n" \
|
45 | 49 | "(branch with no commits) for this repository, you can do so\n" \
|
@@ -613,6 +617,107 @@ static void print_preparing_worktree_line(int detach,
|
613 | 617 | }
|
614 | 618 | }
|
615 | 619 |
|
| 620 | +/** |
| 621 | + * Callback to short circuit iteration over refs on the first reference |
| 622 | + * corresponding to a valid oid. |
| 623 | + * |
| 624 | + * Returns 0 on failure and non-zero on success. |
| 625 | + */ |
| 626 | +static int first_valid_ref(const char *refname, |
| 627 | + const struct object_id *oid, |
| 628 | + int flags, |
| 629 | + void *cb_data) |
| 630 | +{ |
| 631 | + return 1; |
| 632 | +} |
| 633 | + |
| 634 | +/** |
| 635 | + * Verifies HEAD and determines whether there exist any valid local references. |
| 636 | + * |
| 637 | + * - Checks whether HEAD points to a valid reference. |
| 638 | + * |
| 639 | + * - Checks whether any valid local branches exist. |
| 640 | + * |
| 641 | + * Returns 1 if any of the previous checks are true, otherwise returns 0. |
| 642 | + */ |
| 643 | +static int can_use_local_refs(const struct add_opts *opts) |
| 644 | +{ |
| 645 | + if (head_ref(first_valid_ref, NULL)) { |
| 646 | + return 1; |
| 647 | + } else if (for_each_branch_ref(first_valid_ref, NULL)) { |
| 648 | + return 1; |
| 649 | + } |
| 650 | + return 0; |
| 651 | +} |
| 652 | + |
| 653 | +/** |
| 654 | + * Reports whether the necessary flags were set and whether the repository has |
| 655 | + * remote references to attempt DWIM tracking of upstream branches. |
| 656 | + * |
| 657 | + * 1. Checks that `--guess-remote` was used or `worktree.guessRemote = true`. |
| 658 | + * |
| 659 | + * 2. Checks whether any valid remote branches exist. |
| 660 | + * |
| 661 | + * 3. Checks that there exists at least one remote and emits a warning/error |
| 662 | + * if both checks 1. and 2. are false (can be bypassed with `--force`). |
| 663 | + * |
| 664 | + * Returns 1 if checks 1. and 2. are true, otherwise 0. |
| 665 | + */ |
| 666 | +static int can_use_remote_refs(const struct add_opts *opts) |
| 667 | +{ |
| 668 | + if (!guess_remote) { |
| 669 | + if (!opts->quiet) |
| 670 | + fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT); |
| 671 | + return 0; |
| 672 | + } else if (for_each_remote_ref(first_valid_ref, NULL)) { |
| 673 | + return 1; |
| 674 | + } else if (!opts->force && remote_get(NULL)) { |
| 675 | + die(_("No local or remote refs exist despite at least one remote\n" |
| 676 | + "present, stopping; use 'add -f' to overide or fetch a remote first")); |
| 677 | + } else if (!opts->quiet) { |
| 678 | + fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT); |
| 679 | + } |
| 680 | + return 0; |
| 681 | +} |
| 682 | + |
| 683 | +/** |
| 684 | + * Determines whether `--orphan` should be inferred in the evaluation of |
| 685 | + * `worktree add path/` or `worktree add -b branch path/` and emits an error |
| 686 | + * if the supplied arguments would produce an illegal combination when the |
| 687 | + * `--orphan` flag is included. |
| 688 | + * |
| 689 | + * `opts` and `opt_track` contain the other options & flags supplied to the |
| 690 | + * command. |
| 691 | + * |
| 692 | + * remote determines whether to check `can_use_remote_refs()` or not. This |
| 693 | + * is primarily to differentiate between the basic `add` DWIM and `add -b`. |
| 694 | + * |
| 695 | + * Returns 1 when inferring `--orphan`, 0 otherwise, and emits an error when |
| 696 | + * `--orphan` is inferred but doing so produces an illegal combination of |
| 697 | + * options and flags. Additionally produces an error when remote refs are |
| 698 | + * checked and the repo is in a state that looks like the user added a remote |
| 699 | + * but forgot to fetch (and did not override the warning with -f). |
| 700 | + */ |
| 701 | +static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote) |
| 702 | +{ |
| 703 | + if (can_use_local_refs(opts)) { |
| 704 | + return 0; |
| 705 | + } else if (remote && can_use_remote_refs(opts)) { |
| 706 | + return 0; |
| 707 | + } else if (!opts->quiet) { |
| 708 | + fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT); |
| 709 | + } |
| 710 | + |
| 711 | + if (opt_track) { |
| 712 | + die(_("'%s' and '%s' cannot be used together"), "--orphan", |
| 713 | + "--track"); |
| 714 | + } else if (!opts->checkout) { |
| 715 | + die(_("'%s' and '%s' cannot be used together"), "--orphan", |
| 716 | + "--no-checkout"); |
| 717 | + } |
| 718 | + return 1; |
| 719 | +} |
| 720 | + |
616 | 721 | static const char *dwim_branch(const char *path, const char **new_branch)
|
617 | 722 | {
|
618 | 723 | int n;
|
@@ -723,12 +828,19 @@ static int add(int ac, const char **av, const char *prefix)
|
723 | 828 | int n;
|
724 | 829 | const char *s = worktree_basename(path, &n);
|
725 | 830 | new_branch = xstrndup(s, n);
|
726 |
| - } else if (new_branch || opts.detach || opts.orphan) { |
| 831 | + } else if (opts.orphan || opts.detach) { |
727 | 832 | // No-op
|
| 833 | + } else if (ac < 2 && new_branch) { |
| 834 | + // DWIM: Infer --orphan when repo has no refs. |
| 835 | + opts.orphan = dwim_orphan(&opts, !!opt_track, 0); |
728 | 836 | } else if (ac < 2) {
|
| 837 | + // DWIM: Guess branch name from path. |
729 | 838 | const char *s = dwim_branch(path, &new_branch);
|
730 | 839 | if (s)
|
731 | 840 | branch = s;
|
| 841 | + |
| 842 | + // DWIM: Infer --orphan when repo has no refs. |
| 843 | + opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1); |
732 | 844 | } else if (ac == 2) {
|
733 | 845 | struct object_id oid;
|
734 | 846 | struct commit *commit;
|
|
0 commit comments