From patchwork Mon Jun 8 06:23:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592583 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A68A4912 for ; Mon, 8 Jun 2020 06:25:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 83CFA2067B for ; Mon, 8 Jun 2020 06:25:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="umqM+nXw" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728702AbgFHGZB (ORCPT ); Mon, 8 Jun 2020 02:25:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51924 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728334AbgFHGZA (ORCPT ); Mon, 8 Jun 2020 02:25:00 -0400 Received: from mail-io1-xd42.google.com (mail-io1-xd42.google.com [IPv6:2607:f8b0:4864:20::d42]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D06CC08C5C4 for ; Sun, 7 Jun 2020 23:25:00 -0700 (PDT) Received: by mail-io1-xd42.google.com with SMTP id c8so17341669iob.6 for ; Sun, 07 Jun 2020 23:25:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=d8pRSLGaGRrEW4htbLAXHZG5waVEBVHSPXOCB1NQdew=; b=umqM+nXwT8JPfYDrlgfBIEe+5gSupUILemlPqtbhkG0SPoPs4gD0DvWLj3e/gZmnES SD2rZQep5aYTV4WqLwxVyYMAZ04jyVPqD3WY4kADFEljkMDQSx4ZxHE8wsCLM3lyzp7S k5H3JcySJXD5ky9J8nxI6KrwRUr9wZDrkc10d7zXUTQift9j12/ZEeVRVpm5fg2slqBY rUOA7SEvs/b0fte9eIpc3N5wDzJ2Ce1EpDWeoxxuQ/wVOl8tiK7jzYvAcxZguI35B/gi ZLehIZpxC+S9sRnHu5FACbTjanLhldVZdiovQwY0d76fR40EbQ1wj7iBkKpA3s3vZKlK IF8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=d8pRSLGaGRrEW4htbLAXHZG5waVEBVHSPXOCB1NQdew=; b=DXKBOi26/tN3+08dEqs7j3cUvMnnwrcC+N/QHaJ0mbULfXDLTx+wVGabyLCQvGTBHi 3OVT/ZYmTeOqMW+rrUJPoYet++z5ohFkc4JWuQDY+WMb3AZW2AmhGGfGC6i3KzghT5Yr 5QjRkLmf13XKYi6d3J8BZYFwuojqQZh+cpLOPqo03V7avJ1XArmVDSKZ8Ze9oVF7z0m7 Jm6sqbVvMLaSeIFdI95kHoyttWFEpqbtkzwLdxesoCwHzugYysPn8Ub19slXRf7y0Hm2 hU9qZ7kSDrzJf1yqPWZYhTvvNbJFHn07AwKPYIQ4ihSd8zHxXVJHhe7HwXWXDltJ0Seg OrVQ== X-Gm-Message-State: AOAM533VICujw2JSGvcLdM99xHdo2EVXWC96oraOpazX5jDsAMcNbcXa 19KLNmVgyoMSqJm7rYoILKoZVfod9N4= X-Google-Smtp-Source: ABdhPJwPI/CQzMRvMxCevaBuybsL7MWO8TMN9SFIJRiNQLY563GtOxvbt/ohRlK9NCGQhkStnI7Pfg== X-Received: by 2002:a02:a78e:: with SMTP id e14mr20863078jaj.9.1591597499066; Sun, 07 Jun 2020 23:24:59 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.24.57 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:24:58 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 1/8] worktree: factor out repeated string literal Date: Mon, 8 Jun 2020 02:23:49 -0400 Message-Id: <20200608062356.40264-2-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org For each worktree removed by "git worktree prune", it reports the reason for the removal. All reasons share the common prefix "Removing worktrees/%s:". As new removal reasons are added, this prefix needs to be duplicated, which is error-prone and potentially cumbersome. Therefore, factor out the common prefix. Although this change seems to increase the "sentence lego quotient", it should be reasonably safe, as the reason for removal is a distinct clause, not strictly related to the prefix. Moreover, the "worktrees" in "Removing worktrees/%s:" is a path literal which ought not be localized, so by factoring it out, we can more easily avoid exposing that path fragment to translators. Signed-off-by: Eric Sunshine --- builtin/worktree.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index d99db35668..9b15f19fc5 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -76,19 +76,19 @@ static int prune_worktree(const char *id, struct strbuf *reason) ssize_t read_result; if (!is_directory(git_path("worktrees/%s", id))) { - strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), 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_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id); + 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, _("Removing worktrees/%s: unable to read gitdir file (%s)"), - id, strerror(errno)); + strbuf_addf(reason, _("unable to read gitdir file (%s)"), + strerror(errno)); return 1; } len = xsize_t(st.st_size); @@ -96,8 +96,8 @@ static int prune_worktree(const char *id, struct strbuf *reason) read_result = read_in_full(fd, path, len); if (read_result < 0) { - strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"), - id, strerror(errno)); + strbuf_addf(reason, _("unable to read gitdir file (%s)"), + strerror(errno)); close(fd); free(path); return 1; @@ -106,15 +106,15 @@ static int prune_worktree(const char *id, struct strbuf *reason) if (read_result != len) { strbuf_addf(reason, - _("Removing worktrees/%s: short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"), - id, (uintmax_t)len, (uintmax_t)read_result); + _("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_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id); + strbuf_addstr(reason, _("invalid gitdir file")); free(path); return 1; } @@ -123,7 +123,7 @@ static int prune_worktree(const char *id, struct strbuf *reason) free(path); if (stat(git_path("worktrees/%s/index", id), &st) || st.st_mtime <= expire) { - strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id); + strbuf_addstr(reason, _("gitdir file points to non-existent location")); return 1; } else { return 0; @@ -147,7 +147,8 @@ static void prune_worktrees(void) if (!prune_worktree(d->d_name, &reason)) continue; if (show_only || verbose) - printf("%s\n", reason.buf); + printf_ln(_("Removing %s/%s: %s"), + "worktrees", d->d_name, reason.buf); if (show_only) continue; delete_git_dir(d->d_name); From patchwork Mon Jun 8 06:23:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592589 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3968D912 for ; Mon, 8 Jun 2020 06:25:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1EE892076C for ; Mon, 8 Jun 2020 06:25:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BjpsWTR5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728928AbgFHGZE (ORCPT ); Mon, 8 Jun 2020 02:25:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51930 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728334AbgFHGZB (ORCPT ); Mon, 8 Jun 2020 02:25:01 -0400 Received: from mail-il1-x142.google.com (mail-il1-x142.google.com [IPv6:2607:f8b0:4864:20::142]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5722CC08C5C3 for ; Sun, 7 Jun 2020 23:25:01 -0700 (PDT) Received: by mail-il1-x142.google.com with SMTP id l6so15681650ilo.2 for ; Sun, 07 Jun 2020 23:25:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=whdnnkmjw/vW6hMpYZTnY2nW9IjTmi0t9yHuZThitD0=; b=BjpsWTR5n5xn7euPZlOAWtMi05Zka+Og0IyK6pgj+AYg1AybFI79+4ZeruiJyK2c71 UtlzeIdLaqSxUvRj00I0xz8cRZBh7VAHidlX5wAAgKMPlSG1K0NkeCv+Ng35Ix6UwPpg JRJh0FwcREM2IB/JocsjOzaPEE/tG3WZ0rT45GMiz/RB9s2tS8hfFrkyvmr8NCkhOL6D PtRO1BgxhtS0aeof2PO9RNFTMH9LxRlLTbpCodjVlIJpxVLwZMYKcG0cX5jy0bVLS5wq Uyg2/FvUpAJxUTsKssit+AuZ9loAAVhj0mszwC0VPne+xKIK3szmMdIXNhqUU1CGqb8k 7flQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=whdnnkmjw/vW6hMpYZTnY2nW9IjTmi0t9yHuZThitD0=; b=UU0KESh0bxlj2tECr3nTqV4t6D0OL053Htoo3HDywAWoPnZMX8ow7JHzlIjA1K0T+o NBmpXE2P6xP195pST2eYaVX1DGHaKNosD4DTFmXu/JkTvt3jwe3wvHIr4QYpivcaHCjv EuWHfvzHuWE6us8W7Dwamct6WArjkXlT5Mlq+WBaK/KIdqTmBRrphirIUwcihBX9OIrM 3zXjKs/jABv+ROnE3IBRqVl2BXx1BB+Tghe16+UIkadkvTuEBQPAOjPTiBcJWHGc/EaP zZ0uf7mJmqSbrolOvpmNT724lSQGg5SFzgy/h5nbXBC6M1Xm7IuwJJjrYuAm2XAPidvI hNtg== X-Gm-Message-State: AOAM530gU3nnDjw1WKYRgBRXe23k5Wurot9b0bvlYQowxqNeUmgcLqBk zLxcpbUbGz1c24EypNHXakfsiSwfo+0= X-Google-Smtp-Source: ABdhPJy5zN1LWIvHK851xryxM3GnPRwQGHye7IAAD1L7yhp9LMhQfPBYVgc1ClEeuipy/T/T6Gcdvg== X-Received: by 2002:a05:6e02:812:: with SMTP id u18mr20273848ilm.257.1591597500220; Sun, 07 Jun 2020 23:25:00 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.24.59 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:24:59 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 2/8] worktree: prune corrupted worktree even if locked Date: Mon, 8 Jun 2020 02:23:50 -0400 Message-Id: <20200608062356.40264-3-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The .git/worktrees//locked file created by "git worktree lock" is intended to prevent a missing worktree -- which might reside on a removable device or network share -- from being pruned. It is not meant to prevent a corrupt worktree from being pruned, yet it short-circuits almost all "git worktree prune" corruption checks. This can make it impossible[1] to prune a worktree which becomes corrupt after the lock is placed since "git worktree prune" won't prune it, and it may not even be possible to unlock it with "git worktree unlock", depending upon the nature of the corruption. Therefore, delay the check for .git/worktrees//locked until after all forms of corruption have been checked so that it behaves as originally intended (to wit: preventing pruning of a missing worktree only). [1]: Impossible, that is, without manually mucking around with .git/worktrees// administrative files. Signed-off-by: Eric Sunshine --- builtin/worktree.c | 4 ++-- t/t2401-worktree-prune.sh | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index 9b15f19fc5..f7351413af 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -79,8 +79,6 @@ static int prune_worktree(const char *id, struct strbuf *reason) 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; @@ -121,6 +119,8 @@ static int prune_worktree(const char *id, struct strbuf *reason) path[len] = '\0'; if (!file_exists(path)) { free(path); + if (file_exists(git_path("worktrees/%s/locked", id))) + return 0; if (stat(git_path("worktrees/%s/index", id), &st) || st.st_mtime <= expire) { strbuf_addstr(reason, _("gitdir file points to non-existent location")); diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index b7d6d5d45a..9be8e97d66 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -69,13 +69,23 @@ test_expect_success 'prune directories with gitdir pointing to nowhere' ' ' test_expect_success 'not prune locked checkout' ' - test_when_finished rm -r .git/worktrees && - mkdir -p .git/worktrees/ghi && + test_when_finished rm -fr .git/worktrees ghi && + git worktree add ghi && : >.git/worktrees/ghi/locked && + rm -r ghi && git worktree prune && test -d .git/worktrees/ghi ' +test_expect_success 'prune corrupt despite lock' ' + test_when_finished rm -fr .git/worktrees ghi && + mkdir -p .git/worktrees/ghi && + : >.git/worktrees/ghi/gitdir && + : >.git/worktrees/ghi/locked && + git worktree prune && + ! test -d .git/worktrees/ghi +' + test_expect_success 'not prune recent checkouts' ' test_when_finished rm -r .git/worktrees && git worktree add jlm HEAD && From patchwork Mon Jun 8 06:23:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592587 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F3134912 for ; Mon, 8 Jun 2020 06:25:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D8D5F2067B for ; Mon, 8 Jun 2020 06:25:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DxBjVi/z" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728908AbgFHGZD (ORCPT ); Mon, 8 Jun 2020 02:25:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51932 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728906AbgFHGZC (ORCPT ); Mon, 8 Jun 2020 02:25:02 -0400 Received: from mail-io1-xd42.google.com (mail-io1-xd42.google.com [IPv6:2607:f8b0:4864:20::d42]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9114BC08C5C4 for ; Sun, 7 Jun 2020 23:25:02 -0700 (PDT) Received: by mail-io1-xd42.google.com with SMTP id d5so17329580ios.9 for ; Sun, 07 Jun 2020 23:25:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gtTTi3Moj52Wec61Eqd/9nZMIbvD3AKvmVYzePHh0IM=; b=DxBjVi/zlv7lDGzglx5Vsdg4xvgEUSeGmPWgdcnGzTwfwoZHXHKbS1t6KrDbw+W0xd Uf2ajBhSGMSuf2e7qLmEVRcInrCQCFG66/DCLVwIev1r352wLOta84hDMxlF2gBmF+QB /st3fC5VtzX1WYVYNJWRQ1/tspHbnN/lE/aelMMhfpBkdE4Tespp1LDG7DQ5GJGoQVk3 6qSmsuo4CEAI9XW7s98t+L5asfeUkuB3JZab4OwLelGkWLb3wiiQmEy/zazrf1qP4oN8 UpGBOTHs9Gl2iwjTRtba2v/nWaC1n0SobjtQloqTF117gC0ThS5ECzqdNHkl7WBroCqf jiDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=gtTTi3Moj52Wec61Eqd/9nZMIbvD3AKvmVYzePHh0IM=; b=H2UBC25vfYIFKxnRMWeIGHY1JrF20Ax8JyfRWBqH/6aVM3ZT81frINoS13vNNcY2GX UCkYfa5mmTqysDF043cl8wyX3rY94Ot+mQicuTYKqxdIXyBb1LzYWP2Vqjwxvrmoq5vd 1ERiswUoLnPacyQNkf1HRfCUnXdmi6zLzhgFaj9nQAshh2etqyJohfa78tUfXvLkYyIz HrtKGSNE8xqGOsBDhQmeB5v1np9eNptiEF2E5NGYiBrNR9LADjU3p7y/5i9d9RY7I2RJ 7ZFSaSyHdWHLfih5FVjnoCc09myJeyRCvvbX4Urqqqmk63KKf7ro8gta1oxqaZGuCemR KL5w== X-Gm-Message-State: AOAM531pMuXk/SKTGmqkWppwu+rBoaLsNdRt20x+UG55fnoV4aJsOrt8 NyVORFKqpF53354pEOFkYfKs90AdPiI= X-Google-Smtp-Source: ABdhPJwCWATmhtv6+0O3h2d3wuk+t4hF0lrR9eCq0TkHd7qReu4YnFZ8VnZqQDdhDzlw/ybcjwsMcw== X-Received: by 2002:a02:c985:: with SMTP id b5mr20814725jap.22.1591597501472; Sun, 07 Jun 2020 23:25:01 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.25.00 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:25:00 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 3/8] worktree: give "should be pruned?" function more meaningful name Date: Mon, 8 Jun 2020 02:23:51 -0400 Message-Id: <20200608062356.40264-4-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Readers of the name prune_worktree() are likely to expect the function to actually prune a worktree, however, it only answers the question "should this worktree be pruned?". Give it a name more reflective of its true purpose to avoid such confusion. Signed-off-by: Eric Sunshine --- builtin/worktree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index f7351413af..27681a1396 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -67,7 +67,7 @@ static void delete_worktrees_dir_if_empty(void) rmdir(git_path("worktrees")); /* ignore failed removal */ } -static int prune_worktree(const char *id, struct strbuf *reason) +static int should_prune_worktree(const char *id, struct strbuf *reason) { struct stat st; char *path; @@ -144,7 +144,7 @@ static void prune_worktrees(void) if (is_dot_or_dotdot(d->d_name)) continue; strbuf_reset(&reason); - if (!prune_worktree(d->d_name, &reason)) + if (!should_prune_worktree(d->d_name, &reason)) continue; if (show_only || verbose) printf_ln(_("Removing %s/%s: %s"), From patchwork Mon Jun 8 06:23:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592591 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E3A6B1391 for ; Mon, 8 Jun 2020 06:25:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C7AE320774 for ; Mon, 8 Jun 2020 06:25:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="klZUnWRD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728955AbgFHGZK (ORCPT ); Mon, 8 Jun 2020 02:25:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728916AbgFHGZD (ORCPT ); Mon, 8 Jun 2020 02:25:03 -0400 Received: from mail-io1-xd41.google.com (mail-io1-xd41.google.com [IPv6:2607:f8b0:4864:20::d41]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F8DCC08C5C3 for ; Sun, 7 Jun 2020 23:25:03 -0700 (PDT) Received: by mail-io1-xd41.google.com with SMTP id c8so17341794iob.6 for ; Sun, 07 Jun 2020 23:25:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=dduL+xqp+uc1hgwXRLnQEqd86DPk5wZs0F227Ak3BC4=; b=klZUnWRDxVeZItoeOaffNW2siILJfY3Ug8uw+Wzd7TYN2VwMI6QGgUAZ/WUcM9FJC8 sxZCASCft6BfMhcSSt9IDLYfnQbsKLOb8ppLTg7agnuep7mvlp9xF1YYCwOoP/HMd4lI 3Ju7KS9fD4gEan0inuCjYIYZQQKMsf1OZ6tV1hA0aacJcR81dXtgp2K0fdBOT1QoPlsZ Vz9Mj9wqhuk8JAeRXcVGFB1Bbn2B6gZKKlO++gFr/tPyoYPasnRrQkDVCjLXDTlYB+0o Td+nC3+WO4sZxidm0w1oOLaAuhIeGjwqCT1PTpg33Ikn8Z/AjCbA38AwnSfhoxCZjzBu 1+KQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=dduL+xqp+uc1hgwXRLnQEqd86DPk5wZs0F227Ak3BC4=; b=nLveLT0GNmZmy6pd2BHIwMNXhsZARe3ObBTVb8CHBXd/HuNwXgo0eurBNmDxRuF0PW tHFHUQzpP51ER4BYjDPsAEoOE6V1wYsjNdH1oKYGVJ9s962LiaD0cxjudLs62CylL24X p+6kmAHXMJYHRU9yZTHnNT5oUMICsj4YyXi2h4uMmieTmvE082wnmkFkFcQ3vvzQISrI dhyTYqJlJjtuPwuAnScKMCyc+KTcChcbSz1Q2RWzfSkcPtOx+I8ywZK/kziD1lTpZgfl 78NO0oY9/nrxNRrdRtbMpjNLMiazJAFXR1zf7sZ/Gu5bgLnqDfbxpwgp26r78omlELHQ 9Hpw== X-Gm-Message-State: AOAM531vPjRyLtTIvsEhcveOq42NAcOy8FQ/XehRf4mdnMDy6cZoIOvN jW9h82JISbahMVUGs4IzWJr8di5Okkw= X-Google-Smtp-Source: ABdhPJwa/d0K4zy41GegIL5CKsBGHPK7waUqEZ6dfu4Ofta+w9qLbYdcrYa7CN2+DbUdU9/6qR0lKQ== X-Received: by 2002:a05:6638:10b:: with SMTP id x11mr19835995jao.109.1591597502608; Sun, 07 Jun 2020 23:25:02 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.25.01 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:25:01 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 4/8] worktree: make high-level pruning re-usable Date: Mon, 8 Jun 2020 02:23:52 -0400 Message-Id: <20200608062356.40264-5-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The low-level logic for removing a worktree is well encapsulated in delete_git_dir(). However, high-level details related to pruning a worktree -- such as dealing with verbosity and dry-run mode -- are not encapsulated. Factor out this high-level logic into its own function so it can be re-used as new worktree corruption detectors are added. Signed-off-by: Eric Sunshine --- builtin/worktree.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index 27681a1396..d0c046e885 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -133,6 +133,14 @@ static int should_prune_worktree(const char *id, struct strbuf *reason) return 0; } +static void prune_worktree(const char *id, const char *reason) +{ + if (show_only || verbose) + printf_ln(_("Removing %s/%s: %s"), "worktrees", id, reason); + if (!show_only) + delete_git_dir(id); +} + static void prune_worktrees(void) { struct strbuf reason = STRBUF_INIT; @@ -146,12 +154,7 @@ static void prune_worktrees(void) strbuf_reset(&reason); if (!should_prune_worktree(d->d_name, &reason)) continue; - if (show_only || verbose) - printf_ln(_("Removing %s/%s: %s"), - "worktrees", d->d_name, reason.buf); - if (show_only) - continue; - delete_git_dir(d->d_name); + prune_worktree(d->d_name, reason.buf); } closedir(dir); if (!show_only) From patchwork Mon Jun 8 06:23:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592599 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5E8531391 for ; Mon, 8 Jun 2020 06:25:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3F9CF2076C for ; Mon, 8 Jun 2020 06:25:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OqRJry9o" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728953AbgFHGZJ (ORCPT ); Mon, 8 Jun 2020 02:25:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51946 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728931AbgFHGZF (ORCPT ); Mon, 8 Jun 2020 02:25:05 -0400 Received: from mail-il1-x143.google.com (mail-il1-x143.google.com [IPv6:2607:f8b0:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F353DC08C5C4 for ; Sun, 7 Jun 2020 23:25:04 -0700 (PDT) Received: by mail-il1-x143.google.com with SMTP id a13so15654284ilh.3 for ; Sun, 07 Jun 2020 23:25:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ajv9ZRjOU5I1TtLHtSsOg0sPmCHp4QOcLkvJb4PbdUM=; b=OqRJry9oVAMgKGc1DRrHS3Otuln3SeSqC+IL5ZW1g2Mw3oKb1CatimXy/KxP8IrMgz eX2d/LfQUR5SJmc9hfX8MdwILfZWXzgZ9rBkn3uuHT+w8EtKPovx415QDW2ULA54TMSt vgFdwcHfRbgfEdy/RXwCQdnXrDqNAQaq2b3mRkmdH6hBS6nIYaJ9RNwLeH890gIe+q8k pO2aOSG4BXm8DZusv+zOuGupDBYobuoL30NFOA4FzQB2B6bp9+IuxHMDZ81GepKsDvR2 Djbmx3g/y62xf+4k32v7dfb1NzGfdx51uzxnSKZHhawzSd5xpqp5Ijlkm6y+TXgGZ0L+ 9/7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=ajv9ZRjOU5I1TtLHtSsOg0sPmCHp4QOcLkvJb4PbdUM=; b=Y1SeBAqgEKq3esQbSccFBso04j8gOYCsVG1SLI7ahK89iO5F/vihHy4EJfUsK5vX/J G9iOSxEm/SyXAtd0dRsIRHU5Sn7szleUjigggkCjtQyuzsP/CGvCx96MKEz8EWuw5esk 8zb4eJmo4VS+iN/l19sp74uXwEVTvx3KUqFutNrDsvPdanwRrxEFo+vMP6eNTgAIS2UR 34AugNIXg6v6Ycq1eXoYG0Y3a2O5dAa+04n+6Nn76A7tyX40+2BqeBQlddBoUMIkf7GW swwpPcUSaZTZ6MY9Fi68hEvBs4RkUCM9DuImrUEVn+ETjVru2BDZklrrG/vLnicAuo/S vHlQ== X-Gm-Message-State: AOAM53357sEXMbuD2/I1nzlhwgcx3on0PedAsqtbHbmrDZLPwB1GUwoI o88ByBzWAz3wQei/uAM0f+eXrFhQou0= X-Google-Smtp-Source: ABdhPJy1lQX7j6kSb8Ya8+fAItDXHvdlaVeUA5QQgZjh5py+ejKiqMe2pYKHyoUImotpBZ7w4mPvxQ== X-Received: by 2002:a92:a1cc:: with SMTP id b73mr8355542ill.162.1591597503746; Sun, 07 Jun 2020 23:25:03 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.25.02 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:25:03 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 5/8] worktree: prune duplicate entries referencing same worktree path Date: Mon, 8 Jun 2020 02:23:53 -0400 Message-Id: <20200608062356.40264-6-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org A fundamental restriction of linked working trees is that there must only ever be a single worktree associated with a particular path, thus "git worktree add" explicitly disallows creation of a new worktree at the same location as an existing registered worktree. Nevertheless, users can still "shoot themselves in the foot" by mucking with administrative files in .git/worktree//. Worse, "git worktree move" is careless[1] and allows a worktree to be moved atop a registered but missing worktree (which can happen, for instance, if the worktree is on removable media). For instance: $ git clone foo.git $ cd foo $ git worktree add ../bar $ git worktree add ../baz $ rm -rf ../bar $ git worktree move ../baz ../bar $ git worktree list .../foo beefd00f [master] .../bar beefd00f [bar] .../bar beefd00f [baz] Help users recover from this form of corruption by teaching "git worktree prune" to detect when multiple worktrees are associated with the same path. [1]: A subsequent commit will fix "git worktree move" validation to be more strict. Signed-off-by: Eric Sunshine --- builtin/worktree.c | 64 ++++++++++++++++++++++++++++++--------- t/t2401-worktree-prune.sh | 12 ++++++++ 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index d0c046e885..2cb95f16d4 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -67,7 +67,12 @@ static void delete_worktrees_dir_if_empty(void) rmdir(git_path("worktrees")); /* ignore failed removal */ } -static int should_prune_worktree(const char *id, struct strbuf *reason) +/* + * Return NULL if worktree entry should be pruned (along with reason for + * pruning), otherwise return the path of the worktree itself. Caller is + * responsible for freeing return value. + */ +static char *worktree_disposition(const char *id, struct strbuf *reason) { struct stat st; char *path; @@ -77,17 +82,17 @@ static int should_prune_worktree(const char *id, struct strbuf *reason) if (!is_directory(git_path("worktrees/%s", id))) { strbuf_addstr(reason, _("not a valid directory")); - return 1; + return NULL; } if (stat(git_path("worktrees/%s/gitdir", id), &st)) { strbuf_addstr(reason, _("gitdir file does not exist")); - return 1; + return NULL; } 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; + return NULL; } len = xsize_t(st.st_size); path = xmallocz(len); @@ -98,7 +103,7 @@ static int should_prune_worktree(const char *id, struct strbuf *reason) strerror(errno)); close(fd); free(path); - return 1; + return NULL; } close(fd); @@ -107,30 +112,29 @@ static int should_prune_worktree(const char *id, struct strbuf *reason) _("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"), (uintmax_t)len, (uintmax_t)read_result); free(path); - return 1; + return NULL; } while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) len--; if (!len) { strbuf_addstr(reason, _("invalid gitdir file")); free(path); - return 1; + return NULL; } path[len] = '\0'; if (!file_exists(path)) { - free(path); if (file_exists(git_path("worktrees/%s/locked", id))) - return 0; + return path; if (stat(git_path("worktrees/%s/index", id), &st) || st.st_mtime <= expire) { strbuf_addstr(reason, _("gitdir file points to non-existent location")); - return 1; + free(path); + return NULL; } else { - return 0; + return path; } } - free(path); - return 0; + return path; } static void prune_worktree(const char *id, const char *reason) @@ -141,22 +145,54 @@ static void prune_worktree(const char *id, const char *reason) delete_git_dir(id); } +static int prune_cmp(const void *a, const void *b) +{ + const struct string_list_item *x = a; + const struct string_list_item *y = b; + int c; + + if ((c = fspathcmp(x->string, y->string))) + return c; + /* paths same; sort by .git/worktrees/ */ + return strcmp(x->util, y->util); +} + +static void prune_dups(struct string_list *l) +{ + int i; + + QSORT(l->items, l->nr, prune_cmp); + for (i = 1; i < l->nr; i++) { + if (!fspathcmp(l->items[i].string, l->items[i - 1].string)) + prune_worktree(l->items[i].util, "duplicate entry"); + } +} + static void prune_worktrees(void) { struct strbuf reason = STRBUF_INIT; + struct string_list kept = STRING_LIST_INIT_NODUP; DIR *dir = opendir(git_path("worktrees")); struct dirent *d; if (!dir) return; while ((d = readdir(dir)) != NULL) { + char *path; if (is_dot_or_dotdot(d->d_name)) continue; strbuf_reset(&reason); - if (!should_prune_worktree(d->d_name, &reason)) + path = worktree_disposition(d->d_name, &reason); + if (path) { + string_list_append(&kept, path)->util = xstrdup(d->d_name); continue; + } prune_worktree(d->d_name, reason.buf); } closedir(dir); + + prune_dups(&kept); + string_list_clear(&kept, 1); + if (!show_only) delete_worktrees_dir_if_empty(); strbuf_release(&reason); diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 9be8e97d66..7694f25a16 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -102,4 +102,16 @@ test_expect_success 'not prune proper checkouts' ' test -d .git/worktrees/nop ' +test_expect_success 'prune duplicate (linked/linked)' ' + test_when_finished rm -fr .git/worktrees w1 w2 && + git worktree add --detach w1 && + git worktree add --detach w2 && + sed "s/w2/w1/" .git/worktrees/w2/gitdir >.git/worktrees/w2/gitdir.new && + mv .git/worktrees/w2/gitdir.new .git/worktrees/w2/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "duplicate entry" actual && + test -d .git/worktrees/w1 && + ! test -d .git/worktrees/w2 +' + test_done From patchwork Mon Jun 8 06:23:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592593 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A791A912 for ; Mon, 8 Jun 2020 06:25:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8DC7120774 for ; Mon, 8 Jun 2020 06:25:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iIdtuOm6" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728958AbgFHGZK (ORCPT ); Mon, 8 Jun 2020 02:25:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51948 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728334AbgFHGZG (ORCPT ); Mon, 8 Jun 2020 02:25:06 -0400 Received: from mail-io1-xd44.google.com (mail-io1-xd44.google.com [IPv6:2607:f8b0:4864:20::d44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 065FDC08C5C5 for ; Sun, 7 Jun 2020 23:25:06 -0700 (PDT) Received: by mail-io1-xd44.google.com with SMTP id c8so17341895iob.6 for ; Sun, 07 Jun 2020 23:25:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WvrD21hbRCEn7XqvpiO3X9JAVgezsBtPd/GuDPEv73c=; b=iIdtuOm64CRBT+zlsrPpMF+t5ikcIXHzcFrtmEGd7EU/pK6y4AfB2Prf1OBdHUTBSl tIVBkZ46v0giJASkWT5iANI3+rGefqc0htWNzhUE0GdA9knr/EDcLIfakG8VKXj24din PWQCERIP/jhCoxHXvhR+TPn4ho7cMFJVOMhkyrAYr/a7h6SdM9IflpEOiYTzF9SggoPz X28wDyEIcAuP7BwdNsPNUZ8zOfaacbM20ipkU/AumbVbDvqmDLLfuiqLMVGqIjJ+I/dG XhxuXRujjOVa/U1+/TWH+siLzvV+BzgDdHgJGHSMB4YxDTH3D2gnHM/fpLUZhKBI5B78 s/fA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=WvrD21hbRCEn7XqvpiO3X9JAVgezsBtPd/GuDPEv73c=; b=L6yOtMFdm6oWtC1QfExWEODnlhPkTqfGELZ7+t/hsPGRK1me5JFhSEvjWiVl3wdWzD Y9rcwiZ/QMMs/gUQimGMp8JL/rB3mk8Y/cPMuLeDIDEIHIeeJUc4PYB01qWr6I9azXSE NG6IxnMw520SHTpgGnYMECylkGwlQ/LYceZg7IXjEsWDJSi6mUCpkVQAihbQgjMOu3xX CHnYVNMWXf2Dy34g11rWwgxP5P3YGGfaaSWoDlU249NHj4mLynueixPG1CI0Co/fp9Xq s6ck3k7KHovfGe0o32FqgHGQJIizmoO6yzdzu1oUEodUBbtaJDf2QJ+mab0AB0FM81yA tInA== X-Gm-Message-State: AOAM53324tHA8AcPw9u4THIkLefuveJwH0B85DmOLUGoykD8c+b78reH wRSz3gEYXACNRCXgIGjBNJFpo+3tkBI= X-Google-Smtp-Source: ABdhPJwIOMa6YyfLV0TpYyDJgehCIVh0YZUw/FDdVsGaTdGNmyiKYpl2p13xsZ/oPg/l93F3xgk2OA== X-Received: by 2002:a02:a895:: with SMTP id l21mr19635575jam.82.1591597504964; Sun, 07 Jun 2020 23:25:04 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.25.03 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:25:04 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 6/8] worktree: prune linked worktree referencing main worktree path Date: Mon, 8 Jun 2020 02:23:54 -0400 Message-Id: <20200608062356.40264-7-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org "git worktree prune" detects when multiple entries are associated with the same path and prunes the duplicates, however, it does not detect when a linked worktree points at the path of the main worktree. Although "git worktree add" disallows creating a new worktree with the same path as the main worktree, such a case can arise outside the control of Git even without the user mucking with .git/worktree// administrative files. For instance: $ git clone foo.git $ git -C foo worktree add ../bar $ rm -rf bar $ mv foo bar $ git -C bar worktree list .../bar deadfeeb [master] .../bar deadfeeb [bar] Help the user recover from such corruption by extending "git worktree prune" to also detect when a linked worktree is associated with the path of the main worktree. Reported-by: Jonathan Müller Signed-off-by: Eric Sunshine --- builtin/worktree.c | 10 ++++++++++ t/t2401-worktree-prune.sh | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/builtin/worktree.c b/builtin/worktree.c index 2cb95f16d4..eebd77c46d 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -153,6 +153,11 @@ static int prune_cmp(const void *a, const void *b) if ((c = fspathcmp(x->string, y->string))) return c; + /* paths same; main worktee (util==0) sorts above all others */ + if (!x->util) + return -1; + if (!y->util) + return 1; /* paths same; sort by .git/worktrees/ */ return strcmp(x->util, y->util); } @@ -171,6 +176,7 @@ static void prune_dups(struct string_list *l) static void prune_worktrees(void) { struct strbuf reason = STRBUF_INIT; + struct strbuf main = STRBUF_INIT; struct string_list kept = STRING_LIST_INIT_NODUP; DIR *dir = opendir(git_path("worktrees")); struct dirent *d; @@ -190,6 +196,10 @@ static void prune_worktrees(void) } closedir(dir); + strbuf_add_absolute_path(&main, get_git_common_dir()); + /* massage main worktree absolute path to match 'gitdir' content */ + strbuf_strip_suffix(&main, "/."); + string_list_append(&kept, strbuf_detach(&main, 0)); prune_dups(&kept); string_list_clear(&kept, 1); diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 7694f25a16..5f3db93b31 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -114,4 +114,16 @@ test_expect_success 'prune duplicate (linked/linked)' ' ! test -d .git/worktrees/w2 ' +test_expect_success 'prune duplicate (main/linked)' ' + test_when_finished rm -fr repo wt && + test_create_repo repo && + test_commit -C repo x && + git -C repo worktree add --detach ../wt && + rm -fr wt && + mv repo wt && + git -C wt worktree prune --verbose >actual && + test_i18ngrep "duplicate entry" actual && + ! test -d .git/worktrees/wt +' + test_done From patchwork Mon Jun 8 06:23:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592595 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CC877912 for ; Mon, 8 Jun 2020 06:25:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B280C20774 for ; Mon, 8 Jun 2020 06:25:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="P31MRcdl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728966AbgFHGZN (ORCPT ); Mon, 8 Jun 2020 02:25:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51956 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728943AbgFHGZH (ORCPT ); Mon, 8 Jun 2020 02:25:07 -0400 Received: from mail-il1-x129.google.com (mail-il1-x129.google.com [IPv6:2607:f8b0:4864:20::129]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3D7F1C08C5C6 for ; Sun, 7 Jun 2020 23:25:07 -0700 (PDT) Received: by mail-il1-x129.google.com with SMTP id v11so15645098ilh.1 for ; Sun, 07 Jun 2020 23:25:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=k+bz1xhM48KvzNHMIasj+815fr8XmjW0JGhd0x4mBIc=; b=P31MRcdl8FeRFcNWwFsVMMXnO/0qikYjb0ps47f9geFkKN7xR23PscGxk5qHjTtdR+ qZDjFEpvj1iJ+qJDaklEvFP7mWrccggRNFgTcQwqlWRpNB8Iq3pZO3uA25QkwqtVPwUg xqsNQt27Jr85YeGixyqiWxkueAjrkt4NAWEi8WglR6BT64lmuJq2y2Puv675VtEK+5jK qdr0wiBsaGspwgL9X9sfYfQD3jE+znSXLuJHERNZslpLz0QuWWVmAjuDJ9FjswUIaTQg vAiKJzAk6bQ9hUAKb1OdrCQV6teXLIGPN+1uz6XFKya1WkwphMvqsswunQmcd/5Bsw7P 5K4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=k+bz1xhM48KvzNHMIasj+815fr8XmjW0JGhd0x4mBIc=; b=lOqzWHfcY0qyeNVlzJMkCcx2HwygtlStI826O4IJ4YWpcy1NPsNc3lcl78AwOIfaqP OLb8ReI72vJ2FU9yprDQG6p1mz6FIC+UzP4Rwj8B7kqUxnSLS6ofudEAeha/AjD4ONzh VC6oIV0KUccvM10dBsOPQTHhp7bjeeSx+Fkwx+cQIL1fpKXYqT4RQeAoKfXxOIJERFYu rG4r7D7zzl0+a31EwE4ipqpk/OA5xb29i+6FQebvyZqyKKzb6JuWLidRvG03VBjEqICh WFPTjmxo/Xpd9IoodXVu3Xf2uXYkBPnf5xXSNL9WA4cqrd8J0kAr9PJOkuylUZwSXyxw qZfw== X-Gm-Message-State: AOAM531czWgKFqR8fYNHruU2Rajp4Mu6eQ+pQr+//rc9qK6bBPQQg7So jWhnIMsH1Qtf3MzhoCGvbld7nZfWcsY= X-Google-Smtp-Source: ABdhPJz6gcbgsxlNfiVhYsDOBHM/p66GaX1BftIm0ewOj+u2jYk+RvY9C0s3wdnwS7jdEAyegrkTdg== X-Received: by 2002:a92:8b13:: with SMTP id i19mr20918334ild.46.1591597506131; Sun, 07 Jun 2020 23:25:06 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.25.05 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:25:05 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 7/8] worktree: generalize candidate worktree path validation Date: Mon, 8 Jun 2020 02:23:55 -0400 Message-Id: <20200608062356.40264-8-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org "git worktree add" checks that the specified path is a valid location for a new worktree by ensuring that the path does not already exist and is not already registered to another worktree (a path can be registered but missing, for instance, if it resides on removable media). Since "git worktree add" is not the only command which should perform such validation ("git worktree move" ought to also), generalize the the validation function for use by other callers, as well. Signed-off-by: Eric Sunshine --- builtin/worktree.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index eebd77c46d..7c0637234e 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -274,34 +274,33 @@ static const char *worktree_basename(const char *path, int *olen) return name; } -static void validate_worktree_add(const char *path, const struct add_opts *opts) +/* check that path is viable location for worktree */ +static void check_candidate_path(const char *path, + int force, + struct worktree **worktrees, + const char *cmd) { - struct worktree **worktrees; struct worktree *wt; int locked; if (file_exists(path) && !is_empty_dir(path)) die(_("'%s' already exists"), path); - worktrees = get_worktrees(0); wt = find_worktree_by_path(worktrees, path); if (!wt) - goto done; + return; locked = !!worktree_lock_reason(wt); - if ((!locked && opts->force) || (locked && opts->force > 1)) { + if ((!locked && force) || (locked && force > 1)) { if (delete_git_dir(wt->id)) - die(_("unable to re-add worktree '%s'"), path); - goto done; + die(_("unusable worktree destination '%s'"), path); + return; } if (locked) - die(_("'%s' is a missing but locked worktree;\nuse 'add -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), path); + die(_("'%s' is a missing but locked worktree;\nuse '%s -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), cmd, path); else - die(_("'%s' is a missing but already registered worktree;\nuse 'add -f' to override, or 'prune' or 'remove' to clear"), path); - -done: - free_worktrees(worktrees); + die(_("'%s' is a missing but already registered worktree;\nuse '%s -f' to override, or 'prune' or 'remove' to clear"), cmd, path); } static int add_worktree(const char *path, const char *refname, @@ -318,8 +317,12 @@ static int add_worktree(const char *path, const char *refname, struct commit *commit = NULL; int is_branch = 0; struct strbuf sb_name = STRBUF_INIT; + struct worktree **worktrees; - validate_worktree_add(path, opts); + worktrees = get_worktrees(0); + check_candidate_path(path, opts->force, worktrees, "add"); + free_worktrees(worktrees); + worktrees = NULL; /* is 'refname' a branch or commit? */ if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) && From patchwork Mon Jun 8 06:23:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sunshine X-Patchwork-Id: 11592597 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7513E1391 for ; Mon, 8 Jun 2020 06:25:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5AB6120774 for ; Mon, 8 Jun 2020 06:25:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="o5Jgb/hy" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728962AbgFHGZM (ORCPT ); Mon, 8 Jun 2020 02:25:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728946AbgFHGZI (ORCPT ); Mon, 8 Jun 2020 02:25:08 -0400 Received: from mail-il1-x144.google.com (mail-il1-x144.google.com [IPv6:2607:f8b0:4864:20::144]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4AFDFC08C5C3 for ; Sun, 7 Jun 2020 23:25:08 -0700 (PDT) Received: by mail-il1-x144.google.com with SMTP id l6so15681861ilo.2 for ; Sun, 07 Jun 2020 23:25:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=jNmqK2kDZaqaI/z+axjQhUH36iOAl9JJU+tnx2sC19Q=; b=o5Jgb/hyK/ECHTD5pFBbeum5WUrhvmKWO6H6p4jnssmB2R6ixTA78091eibHRlhXg7 P5Wu/PisWScInTOSVbAQ9xi9kwS04aXSOg5TS8Wc/C0RYNdZlQ4QrGLPNellb7SBusMP BwCh7b5ZwtvIJK3HgRyTdhWicMrtAfuljhuUsu8MPcB0/nIw+QEndi63g/WTMNmSItQ+ jBjKLzc+oWQvocy5C9tlHe4A9a8uRlTYH4knm9cVqWyqVYNVZU/jS6ABia2mgDWQ9VIW LBcIHHqtbjImHekQ+lYx2oldAhzRXRXr/RIJDqmAtoqnJOJ9YK9AFLwaRUszChgGLnOw d+lA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=jNmqK2kDZaqaI/z+axjQhUH36iOAl9JJU+tnx2sC19Q=; b=KvWXUQLUgueiRu0jnYjjVAhCT4BOL6iAdqORFDOVVGc+BcANlPlfwpOYIZZUb+e2cQ fdG0TLjLuCsO5w1ZuNNb1LZNmvxrwkYf/iImQJ+6DGORElHMoryqfsQfXJrABREkfGy5 dzHZSjWV8BeDjTKaVENVf7wXsEcDbLDi/8E8ApaRQlreHDPBMWG7v7hHra6y/InNQ19H h9avdzhanAooi74JgrIn2odlmZH8t4xfMU2wdWy5YeZZUSbq754JNHVZI9/akBdt95Qe NZygpjTi1rBbyeUEtzo1/BU1Qo6c1SlxShBR6tcUcmta2kkvFUgC+fSUUeoMzP52G6Q/ 9dfw== X-Gm-Message-State: AOAM531E2CyVupBW9+fWv9DRRotKWZmfVno7nHJS02YFGB0s993BbUxx vJ0ZpoQR2goLNzxWAHq25loR95VsswM= X-Google-Smtp-Source: ABdhPJwyFymV7YL0z8Ukcgpeimnqeo+atL7m4HG9tKwRZbJ/f4q2lsaUXhBFgYuPK54v20abjKKosg== X-Received: by 2002:a92:d302:: with SMTP id x2mr8117999ila.175.1591597507215; Sun, 07 Jun 2020 23:25:07 -0700 (PDT) Received: from localhost.localdomain (user-12l2dpj.cable.mindspring.com. [69.81.55.51]) by smtp.gmail.com with ESMTPSA id s73sm7477948ilk.41.2020.06.07.23.25.06 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 07 Jun 2020 23:25:06 -0700 (PDT) From: Eric Sunshine To: git@vger.kernel.org Cc: Duy Nguyen , =?utf-8?q?Jonathan_M=C3=BCller?= , Shourya Shukla , Eric Sunshine Subject: [PATCH 8/8] worktree: make "move" refuse to move atop missing registered worktree Date: Mon, 8 Jun 2020 02:23:56 -0400 Message-Id: <20200608062356.40264-9-sunshine@sunshineco.com> X-Mailer: git-send-email 2.27.0.290.gba653c62da In-Reply-To: <20200608062356.40264-1-sunshine@sunshineco.com> References: <20200608062356.40264-1-sunshine@sunshineco.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org "git worktree add" takes special care to avoid creating a new worktree at a location already registered to an existing worktree even if that worktree is missing (which can happen, for instance, if the worktree resides on removable media). "git worktree move", however, is not so careful when validating the destination location and will happily move the source worktree atop the location of a missing worktree. This leads to the anomalous situation of multiple worktrees being associated with the same path, which is expressively forbidden by design. For example: $ git clone foo.git $ cd foo $ git worktree add ../bar $ git worktree add ../baz $ rm -rf ../bar $ git worktree move ../baz ../bar $ git worktree list .../foo beefd00f [master] .../bar beefd00f [bar] .../bar beefd00f [baz] $ git worktree remove ../bar fatal: validation failed, cannot remove working tree: '.../bar' does not point back to '.git/worktrees/bar' Fix this shortcoming by enhancing "git worktree move" to perform the same additional validation of the destination directory as done by "git worktree add". While at it, add a test to verify that "git worktree move" won't move a worktree atop an existing (non-worktree) path -- a restriction which has always been in place but was never tested. Signed-off-by: Eric Sunshine --- Documentation/git-worktree.txt | 4 +++- builtin/worktree.c | 3 +-- t/t2403-worktree-move.sh | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 85d92c9761..4796c3c05e 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -126,7 +126,9 @@ OPTIONS locked working tree path, specify `--force` twice. + `move` refuses to move a locked working tree unless `--force` is specified -twice. +twice. If the destination is already assigned to some other working tree but is +missing (for instance, if `` was deleted manually), then `--force` +allows the move to proceed; use --force twice if the destination is locked. + `remove` refuses to remove an unclean working tree unless `--force` is used. To remove a locked working tree, specify `--force` twice. diff --git a/builtin/worktree.c b/builtin/worktree.c index 7c0637234e..dda7da497c 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -857,8 +857,7 @@ static int move_worktree(int ac, const char **av, const char *prefix) strbuf_trim_trailing_dir_sep(&dst); strbuf_addstr(&dst, sep); } - if (file_exists(dst.buf)) - die(_("target '%s' already exists"), dst.buf); + check_candidate_path(dst.buf, force, worktrees, "move"); validate_no_submodules(wt); diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh index 939d18d728..7035c9d72e 100755 --- a/t/t2403-worktree-move.sh +++ b/t/t2403-worktree-move.sh @@ -112,6 +112,27 @@ test_expect_success 'move locked worktree (force)' ' git worktree move --force --force flump ploof ' +test_expect_success 'refuse to move worktree atop existing path' ' + > bobble && + git worktree add --detach beeble && + test_must_fail git worktree move beeble bobble +' + +test_expect_success 'move atop existing but missing worktree' ' + git worktree add --detach gnoo && + git worktree add --detach pneu && + rm -fr pneu && + test_must_fail git worktree move gnoo pneu && + git worktree move --force gnoo pneu && + + git worktree add --detach nu && + git worktree lock nu && + rm -fr nu && + test_must_fail git worktree move pneu nu && + test_must_fail git worktree --force move pneu nu && + git worktree move --force --force pneu nu +' + test_expect_success 'move a repo with uninitialized submodule' ' git init withsub && (