diff options
author | Junio C Hamano <gitster@pobox.com> | 2021-02-10 14:48:32 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2021-02-10 14:48:32 -0800 |
commit | 02fb21617e0da10c6cadb1c55147299456633bca (patch) | |
tree | 2d8898c1eaf7b4a911b9c0f9c36fdb8d359e359b /builtin | |
parent | Merge branch 'js/rebase-i-commit-cleanup-fix' (diff) | |
parent | worktree: teach `list` verbose mode (diff) | |
download | tgif-02fb21617e0da10c6cadb1c55147299456633bca.tar.xz |
Merge branch 'rs/worktree-list-verbose'
`git worktree list` now annotates worktrees as prunable, shows
locked and prunable attributes in --porcelain mode, and gained
a --verbose option.
* rs/worktree-list-verbose:
worktree: teach `list` verbose mode
worktree: teach `list` to annotate prunable worktree
worktree: teach `list --porcelain` to annotate locked worktree
t2402: ensure locked worktree is properly cleaned up
worktree: teach worktree_lock_reason() to gently handle main worktree
worktree: teach worktree to lazy-load "prunable" reason
worktree: libify should_prune_worktree()
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/worktree.c | 110 |
1 files changed, 35 insertions, 75 deletions
diff --git a/builtin/worktree.c b/builtin/worktree.c index 71287b2da6..1cd5c2016e 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -12,6 +12,7 @@ #include "submodule.h" #include "utf8.h" #include "worktree.h" +#include "quote.h" static const char * const worktree_usage[] = { N_("git worktree add [<options>] <path> [<commit-ish>]"), @@ -67,79 +68,6 @@ static void delete_worktrees_dir_if_empty(void) rmdir(git_path("worktrees")); /* ignore failed removal */ } -/* - * Return true if worktree entry should be pruned, along with the reason for - * pruning. Otherwise, return false and the worktree's path, or NULL if it - * cannot be determined. Caller is responsible for freeing returned path. - */ -static int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath) -{ - struct stat st; - char *path; - int fd; - size_t len; - ssize_t read_result; - - *wtpath = NULL; - if (!is_directory(git_path("worktrees/%s", id))) { - strbuf_addstr(reason, _("not a valid directory")); - return 1; - } - if (file_exists(git_path("worktrees/%s/locked", id))) - return 0; - if (stat(git_path("worktrees/%s/gitdir", id), &st)) { - strbuf_addstr(reason, _("gitdir file does not exist")); - return 1; - } - fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY); - if (fd < 0) { - strbuf_addf(reason, _("unable to read gitdir file (%s)"), - strerror(errno)); - return 1; - } - len = xsize_t(st.st_size); - path = xmallocz(len); - - read_result = read_in_full(fd, path, len); - if (read_result < 0) { - strbuf_addf(reason, _("unable to read gitdir file (%s)"), - strerror(errno)); - close(fd); - free(path); - return 1; - } - close(fd); - - if (read_result != len) { - strbuf_addf(reason, - _("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"), - (uintmax_t)len, (uintmax_t)read_result); - free(path); - return 1; - } - while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) - len--; - if (!len) { - strbuf_addstr(reason, _("invalid gitdir file")); - free(path); - return 1; - } - path[len] = '\0'; - if (!file_exists(path)) { - if (stat(git_path("worktrees/%s/index", id), &st) || - st.st_mtime <= expire) { - strbuf_addstr(reason, _("gitdir file points to non-existent location")); - free(path); - return 1; - } else { - *wtpath = path; - return 0; - } - } - *wtpath = path; - return 0; -} - static void prune_worktree(const char *id, const char *reason) { if (show_only || verbose) @@ -195,7 +123,7 @@ static void prune_worktrees(void) if (is_dot_or_dotdot(d->d_name)) continue; strbuf_reset(&reason); - if (should_prune_worktree(d->d_name, &reason, &path)) + if (should_prune_worktree(d->d_name, &reason, &path, expire)) prune_worktree(d->d_name, reason.buf); else if (path) string_list_append(&kept, path)->util = xstrdup(d->d_name); @@ -642,6 +570,8 @@ static int add(int ac, const char **av, const char *prefix) static void show_worktree_porcelain(struct worktree *wt) { + const char *reason; + printf("worktree %s\n", wt->path); if (wt->is_bare) printf("bare\n"); @@ -652,6 +582,20 @@ static void show_worktree_porcelain(struct worktree *wt) else if (wt->head_ref) printf("branch %s\n", wt->head_ref); } + + reason = worktree_lock_reason(wt); + if (reason && *reason) { + struct strbuf sb = STRBUF_INIT; + quote_c_style(reason, &sb, NULL, 0); + printf("locked %s\n", sb.buf); + strbuf_release(&sb); + } else if (reason) + printf("locked\n"); + + reason = worktree_prune_reason(wt, expire); + if (reason) + printf("prunable %s\n", reason); + printf("\n"); } @@ -660,6 +604,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len) struct strbuf sb = STRBUF_INIT; int cur_path_len = strlen(wt->path); int path_adj = cur_path_len - utf8_strwidth(wt->path); + const char *reason; strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, wt->path); if (wt->is_bare) @@ -677,9 +622,18 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len) strbuf_addstr(&sb, "(error)"); } - if (!is_main_worktree(wt) && worktree_lock_reason(wt)) + reason = worktree_lock_reason(wt); + if (verbose && reason && *reason) + strbuf_addf(&sb, "\n\tlocked: %s", reason); + else if (reason) strbuf_addstr(&sb, " locked"); + reason = worktree_prune_reason(wt, expire); + if (verbose && reason) + strbuf_addf(&sb, "\n\tprunable: %s", reason); + else if (reason) + strbuf_addstr(&sb, " prunable"); + printf("%s\n", sb.buf); strbuf_release(&sb); } @@ -723,12 +677,18 @@ static int list(int ac, const char **av, const char *prefix) struct option options[] = { OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")), + OPT__VERBOSE(&verbose, N_("show extended annotations and reasons, if available")), + OPT_EXPIRY_DATE(0, "expire", &expire, + N_("add 'prunable' annotation to worktrees older than <time>")), OPT_END() }; + expire = TIME_MAX; ac = parse_options(ac, av, prefix, options, worktree_usage, 0); if (ac) usage_with_options(worktree_usage, options); + else if (verbose && porcelain) + die(_("--verbose and --porcelain are mutually exclusive")); else { struct worktree **worktrees = get_worktrees(); int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i; |