From patchwork Sun Jan 17 23:42:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Silva X-Patchwork-Id: 12025919 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CFCDBC433E0 for ; Sun, 17 Jan 2021 23:45:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9CDE4206ED for ; Sun, 17 Jan 2021 23:45:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730818AbhAQXoz (ORCPT ); Sun, 17 Jan 2021 18:44:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730773AbhAQXo3 (ORCPT ); Sun, 17 Jan 2021 18:44:29 -0500 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 964E8C061574 for ; Sun, 17 Jan 2021 15:43:48 -0800 (PST) Received: by mail-ej1-x633.google.com with SMTP id r12so9873049ejb.9 for ; Sun, 17 Jan 2021 15:43:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XJ7/M5veml/bhfAyzkj6s4ZZQ11MxuUob48zFnDpZg4=; b=Gj3fuiugaSjHxoEihVjk2wqlYIzZNUSM2VA0IQvSlFkcnxvmzudkA4oF03k14w9f25 xAZ9CH5zFP1uA/Y4EtAlNzF1It43VoKTtaEmFq+bsT77Hf3R+jtpjy2U7GpluB3KWIiP traGcBZcuJ5PZxr7k/mZHJAwgQjhTqwBYozv3FIwmx51K5c5DyY31+YRidx+mtCqZFyO SXtE4gR065neiJoux6hYM+v1vZUJIpln2nltPyn0pZuqlXVOmwu9BD+e4ay9/T7PTAQd eCTsMZc6hfi/F4KdKTfZUF0Wb9z2JW2L069f9DKvSTvmYdTo6aBAoKoVmCXXSFWGZ06B TTIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XJ7/M5veml/bhfAyzkj6s4ZZQ11MxuUob48zFnDpZg4=; b=cbMx5Z++X7R/6hphQFMtxxefUinP4sYJa6gFFpg36C0X3HqPwom40uNM8YmkdMLpJ9 UlFtN5empT/GpD7o96b1oOmkGujIKjB5gpF2xnknNdlx77TsBKYA1boJeswpySUKkRVV PY7jF48CyicYq5f3IAT+z1tlBLK14816iwmrZgt57MhpMUvgmIn+sNcUUYhAGx1uVQtN yrM0fHzHGMfxHI67SVDTRtjssi9KWKMNFsT/Z90r8JbK0gzBTEues9iLC+IuoRjhYgQ/ PMNZ+eH3BmQo+1t/CZ1y+yWas0edcd3GGfe0T36dI1sJA4gxDw4MNprSVAfrd2BFC0bt s4hw== X-Gm-Message-State: AOAM5316E7rTvGPoT4e5VFCPMmuYFQOhH5Te5jwFLD+1UBZONuW4oxjD kqDH4EqcMN+nGc660vecM9++CBhYB2c= X-Google-Smtp-Source: ABdhPJzkO1JIl+2bSIJUUoFMIYjbE8ozQ1H1UQxQgoGOppE2rgODtHVp2Ig3zQtouBSbEt5IegNCpw== X-Received: by 2002:a17:906:369a:: with SMTP id a26mr14989498ejc.276.1610927026954; Sun, 17 Jan 2021 15:43:46 -0800 (PST) Received: from localhost.localdomain ([79.140.114.246]) by smtp.gmail.com with ESMTPSA id f13sm8639932ejf.42.2021.01.17.15.43.45 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 17 Jan 2021 15:43:46 -0800 (PST) From: Rafael Silva To: git@vger.kernel.org Cc: Eric Sunshine , Phillip Wood , Rafael Silva Subject: [PATCH v2 1/6] worktree: libify should_prune_worktree() Date: Mon, 18 Jan 2021 00:42:39 +0100 Message-Id: <20210117234244.95106-2-rafaeloliveira.cs@gmail.com> X-Mailer: git-send-email 2.30.0.372.gbc7e965391 In-Reply-To: <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> References: <20210104162128.95281-1-rafaeloliveira.cs@gmail.com> <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org As part of teaching "git worktree list" to annotate worktree that is a candidate for pruning, let's move should_prune_worktree() from builtin/worktree.c to worktree.c in order to make part of the worktree public API. should_prune_worktree() knows how to select the given worktree for pruning based on an expiration date, however the expiration value is stored in a static file-scope variable and it is not local to the function. In order to move the function, teach should_prune_worktree() to take the expiration date as an argument and document the new parameter that is not immediately obvious. Also, change the function comment to clearly state that the worktree's path is returned in `wtpath` argument. Helped-by: Eric Sunshine Signed-off-by: Rafael Silva --- builtin/worktree.c | 75 +--------------------------------------------- worktree.c | 68 +++++++++++++++++++++++++++++++++++++++++ worktree.h | 14 +++++++++ 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index 71287b2da6..dd886d5029 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -67,79 +67,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 +122,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); diff --git a/worktree.c b/worktree.c index 821b233479..8ae019af79 100644 --- a/worktree.c +++ b/worktree.c @@ -741,3 +741,71 @@ void repair_worktree_at_path(const char *path, strbuf_release(&realdotgit); strbuf_release(&dotgit); } + +int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire) +{ + 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; +} diff --git a/worktree.h b/worktree.h index f38e6fd5a2..818e1491c7 100644 --- a/worktree.h +++ b/worktree.h @@ -73,6 +73,20 @@ int is_main_worktree(const struct worktree *wt); */ const char *worktree_lock_reason(struct worktree *wt); +/* + * Return true if worktree entry should be pruned, along with the reason for + * pruning. Otherwise, return false and the worktree's path in `wtpath`, or + * NULL if it cannot be determined. Caller is responsible for freeing + * returned path. + * + * `expire` defines a grace period to prune the worktree when its path + * does not exist. + */ +int should_prune_worktree(const char *id, + struct strbuf *reason, + char **wtpath, + timestamp_t expire); + #define WT_VALIDATE_WORKTREE_MISSING_OK (1 << 0) /* From patchwork Sun Jan 17 23:42:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Silva X-Patchwork-Id: 12025935 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6382C433E0 for ; Sun, 17 Jan 2021 23:49:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 86A18206ED for ; Sun, 17 Jan 2021 23:49:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729990AbhAQXsv (ORCPT ); Sun, 17 Jan 2021 18:48:51 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730776AbhAQXob (ORCPT ); Sun, 17 Jan 2021 18:44:31 -0500 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A6B6C061575 for ; Sun, 17 Jan 2021 15:43:49 -0800 (PST) Received: by mail-ej1-x62e.google.com with SMTP id b5so4783571ejv.4 for ; Sun, 17 Jan 2021 15:43:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WtB6iP/LBZmHDxVizQ1ttWEhEJWuAx4NqbPPPy1hEP0=; b=BTHuaHD92kjmcFOdkPjfVU0fmZlIwP5Ncg5RzoGooyG0qpnoiEhNgIWoawWp60Uy+p mQClkFUKtjMHb/nckVJs9MnZnp5b8GLDCMkEt7T8H644CnahkWI2nzBYhVUDPsm0b+ey dm8ST0MruvhPa2Rzi05YCO/mha2acRPYa5hesmKm8QVMbfwuer77UrJZsZLIaBfzKvQ7 xku7OsdEGhzyHz9weDUk+NGoOa78joulu5wfT3jzzbjfuz9q+r0Jms+plYXYsJL1hPMc fCkRlbx/w0jgXcOBARb/Zsw9Uo2rsfGGCe1A08mhtjkiKrnUY5PBdUxSD0vQcSW292Rm DDeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WtB6iP/LBZmHDxVizQ1ttWEhEJWuAx4NqbPPPy1hEP0=; b=J+mMHgcvjT1+VW4NCHDKBtUAs7RWpt1xVjDUNun5BGN12oZXYNqA7vgm9UCDKK0qpR n/5KLlgcQ0bUvh9rJC+HE7nI2r1pWfN+t41qcJxLBJQhIWKfdP07dRoYriXip32Nbxxr coJPZiFFWBu0Fi+bRAKibIT/XWwSL6DppvZI/rIvID8XKkDoIz+LsSK0rT7yGZlpXAe+ /k/1QrxKTu26nGNEaEiWQ7sqjpCLbpwkprkfRKJ0cfP6tRqhoQzVJLhF0dc5xTLUButF 0Nu0VlLJvDYRcM8X0xczunT4PIaoL2TaUSlJjLenz9aTGarNNh3GUBD0BqOxmir/LdM1 sONQ== X-Gm-Message-State: AOAM532czYUE4JZ2oL/pi0wcuuLulrJMHuY30qThwAy0qMLEpq5djt+j CDKCoekV8E1ZWH1li5X91CdQrnvAI6c= X-Google-Smtp-Source: ABdhPJxi+84stFDuTDlc+cDFKVomEPEQ9W07QItsM2Ll6pdO1KBWnCtwQmThQ544gQrrRR3ZF3lkMw== X-Received: by 2002:a17:906:1288:: with SMTP id k8mr15247454ejb.206.1610927027873; Sun, 17 Jan 2021 15:43:47 -0800 (PST) Received: from localhost.localdomain ([79.140.114.246]) by smtp.gmail.com with ESMTPSA id f13sm8639932ejf.42.2021.01.17.15.43.47 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 17 Jan 2021 15:43:47 -0800 (PST) From: Rafael Silva To: git@vger.kernel.org Cc: Eric Sunshine , Phillip Wood , Rafael Silva Subject: [PATCH v2 2/6] worktree: teach worktree to lazy-load "prunable" reason Date: Mon, 18 Jan 2021 00:42:40 +0100 Message-Id: <20210117234244.95106-3-rafaeloliveira.cs@gmail.com> X-Mailer: git-send-email 2.30.0.372.gbc7e965391 In-Reply-To: <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> References: <20210104162128.95281-1-rafaeloliveira.cs@gmail.com> <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Add worktree_prune_reason() to allow a caller to discover whether a worktree is prunable and the reason that it is, much like worktree_lock_reason() indicates whether a worktree is locked and the reason for the lock. As with worktree_lock_reason(), retrieve the prunable reason lazily and cache it in the `worktree` structure. Helped-by: Eric Sunshine Signed-off-by: Rafael Silva --- worktree.c | 20 ++++++++++++++++++++ worktree.h | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/worktree.c b/worktree.c index 8ae019af79..474ed46562 100644 --- a/worktree.c +++ b/worktree.c @@ -15,6 +15,7 @@ void free_worktrees(struct worktree **worktrees) free(worktrees[i]->id); free(worktrees[i]->head_ref); free(worktrees[i]->lock_reason); + free(worktrees[i]->prune_reason); free(worktrees[i]); } free (worktrees); @@ -245,6 +246,25 @@ const char *worktree_lock_reason(struct worktree *wt) return wt->lock_reason; } +const char *worktree_prune_reason(struct worktree *wt, timestamp_t expire) +{ + struct strbuf reason = STRBUF_INIT; + char *path; + + if (is_main_worktree(wt)) + return NULL; + if (wt->prune_reason_valid) + return wt->prune_reason; + + if (should_prune_worktree(wt->id, &reason, &path, expire)) + wt->prune_reason = strbuf_detach(&reason, NULL); + wt->prune_reason_valid = 1; + + strbuf_release(&reason); + free(path); + return wt->prune_reason; +} + /* convenient wrapper to deal with NULL strbuf */ static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...) { diff --git a/worktree.h b/worktree.h index 818e1491c7..8b7c408132 100644 --- a/worktree.h +++ b/worktree.h @@ -11,11 +11,13 @@ struct worktree { char *id; char *head_ref; /* NULL if HEAD is broken or detached */ char *lock_reason; /* private - use worktree_lock_reason */ + char *prune_reason; /* private - use worktree_prune_reason */ struct object_id head_oid; int is_detached; int is_bare; int is_current; int lock_reason_valid; /* private */ + int prune_reason_valid; /* private */ }; /* @@ -73,6 +75,13 @@ int is_main_worktree(const struct worktree *wt); */ const char *worktree_lock_reason(struct worktree *wt); +/* + * Return the reason string if the given worktree should be pruned, otherwise + * NULL if it should not be pruned. `expire` defines a grace period to prune + * the worktree when its path does not exist. + */ +const char *worktree_prune_reason(struct worktree *wt, timestamp_t expire); + /* * Return true if worktree entry should be pruned, along with the reason for * pruning. Otherwise, return false and the worktree's path in `wtpath`, or From patchwork Sun Jan 17 23:42:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Silva X-Patchwork-Id: 12025937 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A152BC433DB for ; Sun, 17 Jan 2021 23:49:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7155E206E3 for ; Sun, 17 Jan 2021 23:49:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730265AbhAQXso (ORCPT ); Sun, 17 Jan 2021 18:48:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33596 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730778AbhAQXob (ORCPT ); Sun, 17 Jan 2021 18:44:31 -0500 Received: from mail-ed1-x536.google.com (mail-ed1-x536.google.com [IPv6:2a00:1450:4864:20::536]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6E69EC061757 for ; Sun, 17 Jan 2021 15:43:50 -0800 (PST) Received: by mail-ed1-x536.google.com with SMTP id h16so15604006edt.7 for ; Sun, 17 Jan 2021 15:43:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yLwuadH5G7SVc/8uS27TTwjzds3Qilkin/Yl4nAl6fA=; b=aUwagn+J3thSNJ6dEjcN23IlktN+7X0jKu4DTPK5RDZRZlMRoWAZUnz3vnxZQkOpDo lSDupms5yE596NGrfZ+JqY/5/7lSIgETAhfXS49zcAg8AGDCrs+m1y6ZWKROBMyf/q9C 9rlM2+1vh4jg9TA441CQWuO0R4XWx+Nhr+UdxqI1Yd/pOvbChnP8T4g6KCALCiLNZd/f ybyj5lqejDQgxTohob4hacvNnzX4rlcG+jJ8AHmzZ4h7vOVHes68tZodJyuptzgvWzZ8 VcwLAWujQA5/2gzqNVXyHNePpmP/4ZWEH4vKaFA9v6BRCEEz/dj8ySj+jfEcHNiNe57b 9nuw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yLwuadH5G7SVc/8uS27TTwjzds3Qilkin/Yl4nAl6fA=; b=iSxNBUB/aYqqC5BiYtpm66NOie2nXEtIA54iVcMkLgQ0wXereGk4Ac6DFBelldd/QI uYR6SpXys9yUt3XZ+V1HVWZpqKiMfUXgKWr3Uu6uGxw3r8p+shYbF9Lc5YlPVzhC1FNj 5StUT+f3J3ZMd0cTUl7imbyM354koqiKSRhmVPFH3gG3pQ393ojUDeLZX9q69Dyi3fad e8nB7r5kUdTKrcwHdajQf182ME+xMc4ZfA5NxvyQLO6dFP+2JKe/u+8UIn3N3QxU2XK+ QeShPWK6pGHwhuQsYgJgCQWrc/f3yxa3Xvh3ZzUFHzajprivIHXgFnZnS5t3IQFjEMdC qB2Q== X-Gm-Message-State: AOAM532KLWz1tjCCSSRA/qjP4BittBntQBgh2elTVkR7hwAt2YVkvhHk fX1mgt+4Yclo/IUFKs3w1JfmQfzY9Kk= X-Google-Smtp-Source: ABdhPJwHOGPjuc0ZeleR5vtMDxHYsOE/xwjJoHsq4In1OQB9z7wCsbnULOyCVfwsefbqZ154Jqihgg== X-Received: by 2002:a05:6402:1751:: with SMTP id v17mr4414667edx.289.1610927028981; Sun, 17 Jan 2021 15:43:48 -0800 (PST) Received: from localhost.localdomain ([79.140.114.246]) by smtp.gmail.com with ESMTPSA id f13sm8639932ejf.42.2021.01.17.15.43.48 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 17 Jan 2021 15:43:48 -0800 (PST) From: Rafael Silva To: git@vger.kernel.org Cc: Eric Sunshine , Phillip Wood , Rafael Silva Subject: [PATCH v2 3/6] worktree: teach worktree_lock_reason() to gently handle main worktree Date: Mon, 18 Jan 2021 00:42:41 +0100 Message-Id: <20210117234244.95106-4-rafaeloliveira.cs@gmail.com> X-Mailer: git-send-email 2.30.0.372.gbc7e965391 In-Reply-To: <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> References: <20210104162128.95281-1-rafaeloliveira.cs@gmail.com> <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org worktree_lock_reason() aborts with an assertion failure when called on the main worktree since locking the main worktree is nonsensical. Not only is this behaviour undocumented, thus callers might not even be aware that the call could potentially crash the program, but it also forces clients to be extra careful: if (!is_main_worktree(wt) && worktree_locked_reason(...)) ... Since we know that locking makes no sense in the context of the main worktree, we can simpliy return false for the main worktree, thus making client code less complex by eliminating the need for the callers to have inside knowledge about the implementation: if (worktree_lock_reason(...)) ... Helped-by: Eric Sunshine Signed-off-by: Rafael Silva --- worktree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worktree.c b/worktree.c index 474ed46562..39495b261b 100644 --- a/worktree.c +++ b/worktree.c @@ -225,7 +225,8 @@ int is_main_worktree(const struct worktree *wt) const char *worktree_lock_reason(struct worktree *wt) { - assert(!is_main_worktree(wt)); + if (is_main_worktree(wt)) + return NULL; if (!wt->lock_reason_valid) { struct strbuf path = STRBUF_INIT; From patchwork Sun Jan 17 23:42:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Silva X-Patchwork-Id: 12025921 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 637F2C433E6 for ; Sun, 17 Jan 2021 23:45:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 33400206E3 for ; Sun, 17 Jan 2021 23:45:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730827AbhAQXpN (ORCPT ); Sun, 17 Jan 2021 18:45:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730783AbhAQXoc (ORCPT ); Sun, 17 Jan 2021 18:44:32 -0500 Received: from mail-ej1-x629.google.com (mail-ej1-x629.google.com [IPv6:2a00:1450:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F523C0613C1 for ; Sun, 17 Jan 2021 15:43:51 -0800 (PST) Received: by mail-ej1-x629.google.com with SMTP id g3so1833768ejb.6 for ; Sun, 17 Jan 2021 15:43:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=XwhimOFkUCE/aVJgrTw6SY+VMA550OVQFWbC2+zj31Q=; b=iSMlaU781+iv7mWwgCox/kY14d8KZs2gkezmtaxitIDboo/KK3nnXvsRNJ4urSZCtw WiMbkzc3Q2ueX5ywvsYOJCiKZNkHXMCK/4g3eQ7inHOCeaC2AA69qU1ACrPTWv/NnbyJ 8MAJWFJIkDsW+DeklqPl914qebxa3bjlTQXBY34gkyVwJBlLmdcmOTS2U3eMDE6LYdMT vTUuPKKBWs2mgE3teBWtIpN63Zkg28qwEOWXQr+ojyiHLqydOsedsk+039yrr5zocLff 3SQr5UKKDmbJsDZXoqeFKnFtVLA+Qndb71r/kRR/ln6+M4esyNJfg1c/VkxX9mxlE928 V7Yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XwhimOFkUCE/aVJgrTw6SY+VMA550OVQFWbC2+zj31Q=; b=NxU3+Uvirw7oyhsCNtsXV2YrIP3xeh52y97aoNe4A8u94bGc4H5SqBixPiHBcB0ekt 3vHKC3350rNKj1WjfA0Jb4EUWcb3axdVDr2V64oQGUJzGnJzuEvFyJMRNosE5otmNUr4 Vj/JxMla2R3xlfHCwDjraoJ+2TrPIz4wTAJPOryz5t4ZV9hGCtDLRnSFfqEyhhdbarx1 ogkD9/HF5ej9eg6ZAZ+kkmF5r+KEsrGTdyFuqRQAtlLqHYtReCrjFXAW11uX1GECxJgd 6UEdD2oLfPMCWOedXPt/cKp8zUY6eAOF6XfS1lxMgCWY84ahzWmaihFns+hfdp8s9RZe D0SA== X-Gm-Message-State: AOAM532sqHZvUhWGw2bK9PMR1ii3Cu+TOB9pQ5HsMRRBgKwH2LHIcB2y PH+37qpguiGXHKVe+1bOWMMIzkdQS9k= X-Google-Smtp-Source: ABdhPJyWs4UijuiDrc4RTLR2pztnQ/ryZiyjsCSU6UBGwarlcRAT6qN50nW/j+BGJzqLFxUAe8/i6Q== X-Received: by 2002:a17:907:7346:: with SMTP id dq6mr3226904ejc.237.1610927029885; Sun, 17 Jan 2021 15:43:49 -0800 (PST) Received: from localhost.localdomain ([79.140.114.246]) by smtp.gmail.com with ESMTPSA id f13sm8639932ejf.42.2021.01.17.15.43.49 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 17 Jan 2021 15:43:49 -0800 (PST) From: Rafael Silva To: git@vger.kernel.org Cc: Eric Sunshine , Phillip Wood , Rafael Silva Subject: [PATCH v2 4/6] worktree: teach `list --porcelain` to annotate locked worktree Date: Mon, 18 Jan 2021 00:42:42 +0100 Message-Id: <20210117234244.95106-5-rafaeloliveira.cs@gmail.com> X-Mailer: git-send-email 2.30.0.372.gbc7e965391 In-Reply-To: <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> References: <20210104162128.95281-1-rafaeloliveira.cs@gmail.com> <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Commit c57b3367be (worktree: teach `list` to annotate locked worktree, 2020-10-11) taught "git worktree list" to annotate locked worktrees by appending "locked" text to its output, however, this is not listed in the --porcelain format. Teach "list --porcelain" to do the same and add a "locked" attribute followed by its reason, thus making both default and porcelain format consistent. If the locked reason is not available then only "locked" is shown. The output of the "git worktree list --porcelain" becomes like so: $ git worktree list --porcelain ... worktree /path/to/locked HEAD 123abcdea123abcd123acbd123acbda123abcd12 detached locked worktree /path/to/locked-with-reason HEAD abc123abc123abc123abc123abc123abc123abc1 detached locked reason why it is locked ... The locked reason is quoted to prevent newline characters (i.e: LF or CRLF) breaking the --porcelain format as each attribute is shown per line. For example: $ git worktree list --porcelain ... locked worktree's path mounted in\nremovable device ... Furthermore, let's update the documentation to state that some attributes in the porcelain format might be listed alone or together with its value depending whether the value is available or not. Thus documenting the case of the new "locked" attribute. Additionally, c57b3367be (worktree: teach `list` to annotate locked worktree, 2020-10-11) introduced a new test to ensure locked worktrees are listed with "locked" annotation. However, the test does not clean up after itself as "git worktree prune" is not going to remove the locked worktree in the first place. This not only leaves the test in an unclean state it also potentially breaks following tests that relies on the "git worktree list" output. Let's fix that by unlocking the worktree before the "prune" command. Helped-by: Eric Sunshine Signed-off-by: Rafael Silva --- Documentation/git-worktree.txt | 16 ++++++++++++++-- builtin/worktree.c | 13 +++++++++++++ t/t2402-worktree-list.sh | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 02a706c4c0..d352a002f2 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -377,8 +377,10 @@ Porcelain Format The porcelain format has a line per attribute. Attributes are listed with a label and value separated by a single space. Boolean attributes (like `bare` and `detached`) are listed as a label only, and are present only -if the value is true. The first attribute of a working tree is always -`worktree`, an empty line indicates the end of the record. For example: +if the value is true. Some attributes (like `locked`) can be listed as a label +only or with a value depending whether a reason is available. The first +attribute of a working tree is always `worktree`, an empty line indicates the +end of the record. For example: ------------ $ git worktree list --porcelain @@ -393,6 +395,16 @@ worktree /path/to/other-linked-worktree HEAD 1234abc1234abc1234abc1234abc1234abc1234a detached +worktree /path/to/linked-worktree-locked +HEAD 5678abc5678abc5678abc5678abc5678abc5678c +branch refs/heads/locked +locked + +worktree /path/to/linked-worktree-locked-with-reason +HEAD 3456def3456def3456def3456def3456def3456b +branch refs/heads/locked-with-reason +locked reason why is locked + ------------ EXAMPLES diff --git a/builtin/worktree.c b/builtin/worktree.c index dd886d5029..37ae277352 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 [] []"), @@ -569,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"); @@ -579,6 +582,16 @@ 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, CQUOTE_NODQ); + printf("locked %s\n", sb.buf); + strbuf_release(&sb); + } else if (reason) + printf("locked\n"); + printf("\n"); } diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh index 795ddca2e4..c522190feb 100755 --- a/t/t2402-worktree-list.sh +++ b/t/t2402-worktree-list.sh @@ -66,11 +66,43 @@ test_expect_success '"list" all worktrees with locked annotation' ' git worktree add --detach locked master && git worktree add --detach unlocked master && git worktree lock locked && + test_when_finished "git worktree unlock locked" && git worktree list >out && grep "/locked *[0-9a-f].* locked$" out && ! grep "/unlocked *[0-9a-f].* locked$" out ' +test_expect_success '"list" all worktrees --porcelain with locked' ' + test_when_finished "rm -rf locked1 locked2 unlocked out actual expect && git worktree prune" && + echo "locked" >expect && + echo "locked with reason" >>expect && + git worktree add --detach locked1 && + git worktree add --detach locked2 && + git worktree add --detach unlocked && + git worktree lock locked1 && + git worktree lock locked2 --reason "with reason" && + test_when_finished "git worktree unlock locked1 && git worktree unlock locked2" && + git worktree list --porcelain >out && + grep "^locked" out >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees --porcelain with locked reason newline escaped' ' + test_when_finished "rm -rf locked_lf locked_crlf out actual expect && git worktree prune" && + printf "locked locked\\\\r\\\\nreason\n" >expect && + printf "locked locked\\\\nreason\n" >>expect && + git worktree add --detach locked_lf && + git worktree add --detach locked_crlf && + printf "locked\nreason\n\n" >reason_lf && + printf "locked\r\nreason\n\n" >reason_crlf && + git worktree lock locked_lf --reason "$(cat reason_lf)" && + git worktree lock locked_crlf --reason "$(cat reason_crlf)" && + test_when_finished "git worktree unlock locked_lf && git worktree unlock locked_crlf" && + git worktree list --porcelain >out && + grep "^locked" out >actual && + test_cmp expect actual +' + test_expect_success 'bare repo setup' ' git init --bare bare1 && echo "data" >file1 && From patchwork Sun Jan 17 23:42:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Silva X-Patchwork-Id: 12025929 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B20D9C433E0 for ; Sun, 17 Jan 2021 23:46:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 789FC206E3 for ; Sun, 17 Jan 2021 23:46:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730872AbhAQXpq (ORCPT ); Sun, 17 Jan 2021 18:45:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730783AbhAQXpR (ORCPT ); Sun, 17 Jan 2021 18:45:17 -0500 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98FA9C0613CF for ; Sun, 17 Jan 2021 15:43:52 -0800 (PST) Received: by mail-ej1-x62a.google.com with SMTP id a10so4597485ejg.10 for ; Sun, 17 Jan 2021 15:43:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=s4m7NkDtgIh0IrgO1NmV6FFK3XGHDTBWlG2tHRVoM2w=; b=Qo9uurKhM0/+C9Sn9WEsQWW72UIVPeu5QEtrJKsFlDKOFcKFrtepwZ0U+rN3dHSI5G W1gVijQYvD7G1lufGt3feERPa8VIyHM+dNcMuZChei++tVWy8YrN3ORvoI4oJBAOkY0x 66lLszoTPyi/7nCQFEB9tM6tLpPSobTp+50FeTpckPESGKVGam4WI9ezQgIddh+Hftci B6dk22isTnHTVW+nL5prD4xpF2G7CUei9E8D7svTDyFZGD6SUc6pQtYLEDDNbQpjaZmj ZsYRWdZcoYuQl4QCLLDh9/BTHXEYa5Xt35AfCFXnR6i9LrM74suWc/5ifqsL2FV13z5r XYxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=s4m7NkDtgIh0IrgO1NmV6FFK3XGHDTBWlG2tHRVoM2w=; b=dsqPS/zvBFOzaEoxx1V5RNI7PRMNgNzUOEj6yR/LcCDCrgJZI5KlpOlfKjGOUhzwdr 2f1MHtsD2/IZtwNpJkLZQXqgJ5h1M/ff7sAfGktrMptqUoG7PsYsf4dOGpw5v+ar94bR YaJ0O07uVthmTstS06FwbvbW5KUuky/KcWAxljPc+CmcfUc9TlCAw2ZvmsEAbq1o8yjw aTPNizPDCeBIUVk5oJgKYM8tmJwtVJgU8yaDj9LiHrsvo/APg1gw2TX63sPCLkKwXBcQ qUh9qnmnG8g6vvOT2fkG6w/uqbJjI/0mzc41lak7NUwmkXTM4XP9UqKjD+v+eR9J/Kq8 bBjA== X-Gm-Message-State: AOAM531+CBMROooS8GvezPnSihWuOo+xjIg85XyXwf3kJiJqtliDNG6K kbMUcntHBBFLW0TjIKAIkszDisvDVdU= X-Google-Smtp-Source: ABdhPJzLPBysuX5htgdUpmnQPodGuMg6tDsWr0HVI5l+7RB6jllWcfnJ31HPdtXzWyY+jPcPZByE7A== X-Received: by 2002:a17:906:7c49:: with SMTP id g9mr16025699ejp.185.1610927030996; Sun, 17 Jan 2021 15:43:50 -0800 (PST) Received: from localhost.localdomain ([79.140.114.246]) by smtp.gmail.com with ESMTPSA id f13sm8639932ejf.42.2021.01.17.15.43.50 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 17 Jan 2021 15:43:50 -0800 (PST) From: Rafael Silva To: git@vger.kernel.org Cc: Eric Sunshine , Phillip Wood , Rafael Silva Subject: [PATCH v2 5/6] worktree: teach `list` to annotate prunable worktree Date: Mon, 18 Jan 2021 00:42:43 +0100 Message-Id: <20210117234244.95106-6-rafaeloliveira.cs@gmail.com> X-Mailer: git-send-email 2.30.0.372.gbc7e965391 In-Reply-To: <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> References: <20210104162128.95281-1-rafaeloliveira.cs@gmail.com> <20210117234244.95106-1-rafaeloliveira.cs@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The "git worktree list" command shows the absolute path to the worktree, the commit that is checked out, the name of the branch, and a "locked" annotation if the worktree is locked, however, it does not indicate whether the worktree is prunable. The "prune" command will remove a worktree if it is prunable unless `--dry-run` option is specified. This could lead to a worktree being removed without the user realizing before it is too late, in case the user forgets to pass --dry-run for instance. If the "list" command shows which worktree is prunable, the user could verify before running "git worktree prune" and hopefully prevents the working tree to be removed "accidentally" on the worse case scenario. Let's teach "git worktree list" to show when a worktree is a prunable candidate for both default and porcelain format. In the default format a "prunable" text is appended: $ git worktree list /path/to/main aba123 [main] /path/to/linked 123abc [branch-a] /path/to/prunable ace127 (detached HEAD) prunable In the --porcelain format a prunable label is added followed by its reason: $ git worktree list --porcelain ... worktree /path/to/prunable HEAD abc1234abc1234abc1234abc1234abc1234abc12 detached prunable gitdir file points to non-existent location ... Helped-by: Eric Sunshine Signed-off-by: Rafael Silva --- Documentation/git-worktree.txt | 26 ++++++++++++++++++++++++-- builtin/worktree.c | 15 ++++++++++++++- t/t2402-worktree-list.sh | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index d352a002f2..3d8c14dbdf 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -97,8 +97,9 @@ list:: List details of each working tree. The main working tree is listed first, followed by each of the linked working trees. The output details include whether the working tree is bare, the revision currently checked out, the -branch currently checked out (or "detached HEAD" if none), and "locked" if -the worktree is locked. +branch currently checked out (or "detached HEAD" if none), "locked" if +the worktree is locked, "prunable" if the worktree can be pruned by `prune` +command. lock:: @@ -234,6 +235,9 @@ This can also be set up as the default behaviour by using the --expire