From: Junio C Hamano Date: Wed, 6 Jul 2016 20:38:11 +0000 (-0700) Subject: Merge branch 'nd/worktree-cleanup-post-head-protection' X-Git-Tag: v2.10.0-rc0~160 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/7a738b40f67fc44c2a2c1abcffe474241af3d30e?ds=inline;hp=-c Merge branch 'nd/worktree-cleanup-post-head-protection' Further preparatory clean-up for "worktree" feature continues. * nd/worktree-cleanup-post-head-protection: worktree: simplify prefixing paths worktree: avoid 0{40}, too many zeroes, hard to read worktree.c: use is_dot_or_dotdot() git-worktree.txt: keep subcommand listing in alphabetical order worktree.c: rewrite mark_current_worktree() to avoid strbuf completion: support git-worktree --- 7a738b40f67fc44c2a2c1abcffe474241af3d30e diff --combined Documentation/git-worktree.txt index 23d8d2ace0,27feff6dba..7c4cfb0885 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@@ -10,8 -10,8 +10,8 @@@ SYNOPSI -------- [verse] 'git worktree add' [-f] [--detach] [--checkout] [-b ] [] - 'git worktree prune' [-n] [-v] [--expire ] 'git worktree list' [--porcelain] + 'git worktree prune' [-n] [-v] [--expire ] DESCRIPTION ----------- @@@ -48,17 -48,12 +48,13 @@@ add []: Create `` and checkout `` into it. The new working directory is linked to the current repository, sharing everything except working -directory specific files such as HEAD, index, etc. +directory specific files such as HEAD, index, etc. `-` may also be +specified as ``; it is synonymous with `@{-1}`. + If `` is omitted and neither `-b` nor `-B` nor `--detached` used, then, as a convenience, a new branch based at HEAD is created automatically, as if `-b $(basename )` was specified. - prune:: - - Prune working tree information in $GIT_DIR/worktrees. - list:: List details of each worktree. The main worktree is listed first, followed by @@@ -66,6 -61,10 +62,10 @@@ each of the linked worktrees. The outp bare, the revision currently checked out, and the branch currently checked out (or 'detached HEAD' if none). + prune:: + + Prune working tree information in $GIT_DIR/worktrees. + OPTIONS ------- diff --combined builtin/worktree.c index e3199a22e5,f9dac376f7..e866844685 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@@ -13,8 -13,8 +13,8 @@@ static const char * const worktree_usage[] = { N_("git worktree add [] []"), - N_("git worktree prune []"), N_("git worktree list []"), + N_("git worktree prune []"), NULL }; @@@ -95,7 -95,7 +95,7 @@@ static void prune_worktrees(void if (!dir) return; while ((d = readdir(dir)) != NULL) { - if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + if (is_dot_or_dotdot(d->d_name)) continue; strbuf_reset(&reason); if (!prune_worktree(d->d_name, &reason)) @@@ -110,7 -110,7 +110,7 @@@ if (ret < 0 && errno == ENOTDIR) ret = unlink(path.buf); if (ret) - error(_("failed to remove: %s"), strerror(errno)); + error_errno(_("failed to remove '%s'"), path.buf); } closedir(dir); if (!show_only) @@@ -262,7 -262,7 +262,7 @@@ static int add_worktree(const char *pat */ strbuf_reset(&sb); strbuf_addf(&sb, "%s/HEAD", sb_repo.buf); - write_file(sb.buf, "0000000000000000000000000000000000000000"); + write_file(sb.buf, sha1_to_hex(null_sha1)); strbuf_reset(&sb); strbuf_addf(&sb, "%s/commondir", sb_repo.buf); write_file(sb.buf, "../.."); @@@ -337,12 -337,9 +337,12 @@@ static int add(int ac, const char **av if (ac < 1 || ac > 2) usage_with_options(worktree_usage, options); - path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0]; + path = prefix_filename(prefix, strlen(prefix), av[0]); branch = ac < 2 ? "HEAD" : av[1]; + if (!strcmp(branch, "-")) + branch = "@{-1}"; + opts.force_new_branch = !!new_branch_force; if (opts.force_new_branch) { struct strbuf symref = STRBUF_INIT; @@@ -470,6 -467,8 +470,8 @@@ int cmd_worktree(int ac, const char **a if (ac < 2) usage_with_options(worktree_usage, options); + if (!prefix) + prefix = ""; if (!strcmp(av[1], "add")) return add(ac - 1, av + 1, prefix); if (!strcmp(av[1], "prune")) diff --combined contrib/completion/git-completion.bash index ddda5e5e27,951a186df0..37888f4e57 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@@ -803,50 -803,6 +803,50 @@@ __git_find_on_cmdline ( done } +# Echo the value of an option set on the command line or config +# +# $1: short option name +# $2: long option name including = +# $3: list of possible values +# $4: config string (optional) +# +# example: +# result="$(__git_get_option_value "-d" "--do-something=" \ +# "yes no" "core.doSomething")" +# +# result is then either empty (no option set) or "yes" or "no" +# +# __git_get_option_value requires 3 arguments +__git_get_option_value () +{ + local c short_opt long_opt val + local result= values config_key word + + short_opt="$1" + long_opt="$2" + values="$3" + config_key="$4" + + ((c = $cword - 1)) + while [ $c -ge 0 ]; do + word="${words[c]}" + for val in $values; do + if [ "$short_opt$val" = "$word" ] || + [ "$long_opt$val" = "$word" ]; then + result="$val" + break 2 + fi + done + ((c--)) + done + + if [ -n "$config_key" ] && [ -z "$result" ]; then + result="$(git --git-dir="$(__gitdir)" config "$config_key")" + fi + + echo "$result" +} + __git_has_doubledash () { local c=1 @@@ -1142,8 -1098,6 +1142,8 @@@ _git_clone ( esac } +__git_untracked_file_modes="all no normal" + _git_commit () { case "$prev" in @@@ -1165,7 -1119,7 +1165,7 @@@ return ;; --untracked-files=*) - __gitcomp "all no normal" "" "${cur##--untracked-files=}" + __gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}" return ;; --*) @@@ -1826,56 -1780,6 +1826,56 @@@ _git_stage ( _git_add } +_git_status () +{ + local complete_opt + local untracked_state + + case "$cur" in + --ignore-submodules=*) + __gitcomp "none untracked dirty all" "" "${cur##--ignore-submodules=}" + return + ;; + --untracked-files=*) + __gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}" + return + ;; + --column=*) + __gitcomp " + always never auto column row plain dense nodense + " "" "${cur##--column=}" + return + ;; + --*) + __gitcomp " + --short --branch --porcelain --long --verbose + --untracked-files= --ignore-submodules= --ignored + --column= --no-column + " + return + ;; + esac + + untracked_state="$(__git_get_option_value "-u" "--untracked-files=" \ + "$__git_untracked_file_modes" "status.showUntrackedFiles")" + + case "$untracked_state" in + no) + # --ignored option does not matter + complete_opt= + ;; + all|normal|*) + complete_opt="--cached --directory --no-empty-directory --others" + + if [ -n "$(__git_find_on_cmdline "--ignored")" ]; then + complete_opt="$complete_opt --ignored --exclude=*" + fi + ;; + esac + + __git_complete_index_file "$complete_opt" +} + __git_config_get_set_variables () { local prevword word config_file= c=$cword @@@ -2691,6 -2595,29 +2691,29 @@@ _git_whatchanged ( _git_log } + _git_worktree () + { + local subcommands="add list prune" + local subcommand="$(__git_find_on_cmdline "$subcommands")" + if [ -z "$subcommand" ]; then + __gitcomp "$subcommands" + else + case "$subcommand,$cur" in + add,--*) + __gitcomp "--detach" + ;; + list,--*) + __gitcomp "--porcelain" + ;; + prune,--*) + __gitcomp "--dry-run --expire --verbose" + ;; + *) + ;; + esac + fi + } + __git_main () { local i c=1 command __git_dir diff --combined worktree.c index 199b1ef94b,f4a4f38092..e2a94e0476 --- a/worktree.c +++ b/worktree.c @@@ -20,7 -20,7 +20,7 @@@ void free_worktrees(struct worktree **w /* * read 'path_to_ref' into 'ref'. Also if is_detached is not NULL, - * set is_detached to 1 (0) if the ref is detatched (is not detached). + * set is_detached to 1 (0) if the ref is detached (is not detached). * * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses @@@ -153,21 -153,19 +153,19 @@@ done static void mark_current_worktree(struct worktree **worktrees) { - struct strbuf git_dir = STRBUF_INIT; - struct strbuf path = STRBUF_INIT; + char *git_dir = xstrdup(absolute_path(get_git_dir())); int i; - strbuf_addstr(&git_dir, absolute_path(get_git_dir())); for (i = 0; worktrees[i]; i++) { struct worktree *wt = worktrees[i]; - strbuf_addstr(&path, absolute_path(get_worktree_git_dir(wt))); - wt->is_current = !fspathcmp(git_dir.buf, path.buf); - strbuf_reset(&path); - if (wt->is_current) + const char *wt_git_dir = get_worktree_git_dir(wt); + + if (!fspathcmp(git_dir, absolute_path(wt_git_dir))) { + wt->is_current = 1; break; + } } - strbuf_release(&git_dir); - strbuf_release(&path); + free(git_dir); } struct worktree **get_worktrees(void) @@@ -189,7 -187,7 +187,7 @@@ if (dir) { while ((d = readdir(dir)) != NULL) { struct worktree *linked = NULL; - if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + if (is_dot_or_dotdot(d->d_name)) continue; if ((linked = get_linked_worktree(d->d_name))) {