From patchwork Mon Aug 8 19:07:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victoria Dye X-Patchwork-Id: 12939018 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D6C55C25B08 for ; Mon, 8 Aug 2022 19:08:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244233AbiHHTH7 (ORCPT ); Mon, 8 Aug 2022 15:07:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58738 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244191AbiHHTH5 (ORCPT ); Mon, 8 Aug 2022 15:07:57 -0400 Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0929A5584 for ; Mon, 8 Aug 2022 12:07:57 -0700 (PDT) Received: by mail-wm1-x336.google.com with SMTP id ay39-20020a05600c1e2700b003a5503a80cfso666389wmb.2 for ; Mon, 08 Aug 2022 12:07:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc; bh=KmzkJanP+r7zmAbvFVV+dBLWZoBVdjJr9uFqVzfdDDA=; b=jHgGg6/1jfJgy/FD1jG6RJKOAnhxaEOdUYYjMXsKtfbK1jeb5S/q5wtDSwLIk4dm23 UusV7MQCvmJ5twW20aUaHVwT3J5Kodvrj/FTHCRYCW2JKu1u29ymUekXx6uff22jY1Ww ob3ygk3qcM6+2024/AECVWSGdrAh/kDudfW09elxjWmmyFSQ5XxThxkOp7nynMVFjPjw zE2HgJpt0E628UwiBoIqmlt5SVmCZ0Jhn4O/jY3mZwSIQ/UAm2uvb6jgJ3UzrAhCgYdI diRUK7ZG4gg+53HHazNGYAswj3FI5RVwqJXmJBX3vP5YKGvF5RyagHlMjTnF7bu1b/Zz 4N7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc; bh=KmzkJanP+r7zmAbvFVV+dBLWZoBVdjJr9uFqVzfdDDA=; b=uwXtsOcjteqPy2ECIlbJfpuebJDOb3+9zusBnJFyr2Lrl32i8lyIIwVHTG/ldxN1qY nehrONq0AjPgUfOOEpAMwx86DFjS4hNFBuUIs7QhS3ep4SN/jMKFDZZtp5mBpoyLHSxY RVCvmUXvejTzBLmDfcGfEs7Bl+NcgTSMrFMGHdoDhY8M58xHwYVs+dNG+XbEA79zFPYF bel6s/tO2Xq+Jlm0A9DA7ymUNp9RvwLJl5HCgt6iQGd5XUUTHjy6v4QgBDAhmkIPe02m baBF7oWihPPDmPmZ4L6UcZ1qaH5MKrdb1ycR+qaL0GTe+7c12Mo5kYtFf+RTe+ccZc9C PkRQ== X-Gm-Message-State: ACgBeo3hsFdZE0U/2y8Co237dOU3zecdKL03RUSAknepaDoI0Cc0Yy7K cTnZvLRv/LTYHUpiz0vZ+FaKyF4HYzM= X-Google-Smtp-Source: AA6agR4dNjh/AVRgVjotmFxQwksOav3jMXs5CIr/FIqE0qMUfidgwe7NUk8wljrBQqntIhfUMsP2hQ== X-Received: by 2002:a05:600c:5123:b0:3a3:2543:be80 with SMTP id o35-20020a05600c512300b003a32543be80mr18311148wms.155.1659985675227; Mon, 08 Aug 2022 12:07:55 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id j42-20020a05600c1c2a00b003a30c3d0c9csm20433402wms.8.2022.08.08.12.07.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 Aug 2022 12:07:54 -0700 (PDT) Message-Id: <255318f4dc61daef3e892a4dd5c571463985f340.1659985672.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Mon, 08 Aug 2022 19:07:49 +0000 Subject: [PATCH v3 1/4] checkout: fix nested sparse directory diff in sparse index Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: derrickstolee@github.com, shaoxuan.yuan02@gmail.com, newren@gmail.com, gitster@pobox.com, Victoria Dye , Victoria Dye Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Victoria Dye From: Victoria Dye Add the 'recursive' diff flag to the local changes reporting done by 'git checkout' in 'show_local_changes()'. Without the flag enabled, unexpanded sparse directories will not be recursed into to report the diff of each file's contents, resulting in the reported local changes including "modified" sparse directories. The same issue was found and fixed for 'git status' in 2c521b0e49 (status: fix nested sparse directory diff in sparse index, 2022-03-01) Signed-off-by: Victoria Dye --- builtin/checkout.c | 1 + t/t1092-sparse-checkout-compatibility.sh | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/builtin/checkout.c b/builtin/checkout.c index 29c74f898bf..f9d63d80b92 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -626,6 +626,7 @@ static void show_local_changes(struct object *head, repo_init_revisions(the_repository, &rev, NULL); rev.diffopt.flags = opts->flags; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; + rev.diffopt.flags.recursive = 1; diff_setup_done(&rev.diffopt); add_pending_object(&rev, head, NULL); run_diff_index(&rev, 0); diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 763c6cc6846..99a1425a929 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -372,6 +372,14 @@ test_expect_success 'deep changes during checkout' ' test_all_match git checkout base ' +test_expect_success 'checkout with modified sparse directory' ' + init_repos && + + test_all_match git checkout rename-in-to-out -- . && + test_sparse_match git sparse-checkout reapply && + test_all_match git checkout base +' + test_expect_success 'add outside sparse cone' ' init_repos && From patchwork Mon Aug 8 19:07:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victoria Dye X-Patchwork-Id: 12939019 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 102EBC00140 for ; Mon, 8 Aug 2022 19:08:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244265AbiHHTIE (ORCPT ); Mon, 8 Aug 2022 15:08:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58750 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244234AbiHHTH7 (ORCPT ); Mon, 8 Aug 2022 15:07:59 -0400 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3033C38BA for ; Mon, 8 Aug 2022 12:07:58 -0700 (PDT) Received: by mail-wm1-x335.google.com with SMTP id c22so5252629wmr.2 for ; Mon, 08 Aug 2022 12:07:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc; bh=oyrQE6FVXaEt+jquEbYsdAUH9nWe19rHeEkyJVthEdI=; b=WLLzEk0tEpM086uwcSHnfqVAlaswC/LvmnlQi0T/sIXKCEJZve177IShCa70ZTMqLw Ruo2B3sOAEAE8i+9x4erAeIV8ioCu62dSE6cui3w/NZV+19J2fDTaILWoRAId9BUmLJ7 UIxU2SbVqoHnpAKDyLaYz639+3ZfAjWxx0Od9YTO3y0ruAUa8WrmD3XJk2B1B1L4CL5w RXzq8FaXSV3JPG2tx7J2LEImdT8aO3YBfAjYhPbQc5KKqnK2Pk3bI0WFLEujDZyunNLY bR9v/NEo6a2MfQvZJ8TaguKsPz3yVbbzYZXwT0yuoWmj+nd/3QsuwFA7dD/hA3P75sPL 5fBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc; bh=oyrQE6FVXaEt+jquEbYsdAUH9nWe19rHeEkyJVthEdI=; b=et1PaJaUzIniCGaPEofTXnfy1LRHsTbdzRiSgtGzlE/Fy5TEH3+KxBYQJngrQZueLe P/xy0aFCqR1QPbLOJlflXf8d1JfOcOaEQAf7Gdm6mfKU3d32l4dkdl9RSmiDYkoDVj1H gSWgQ69ozHR4+8QoZ36A8MZH+fC4zPWps+f50VwNaWhH2yAGdrMQI/NPiHpYEA75sO3E 8gYNWLs7J+dGVelAShbq7KYSRReITbTadz92FO4LpuEqUg6FCWtxtgYHPcBds1vY3+zQ OzSIVMuvRn2Z8CMZFIFsvDS4id3G2NYAzfIU6InW/WRwt4P1f1tg5ahMwCtrdDhWIeGx YrIw== X-Gm-Message-State: ACgBeo2TsFqxYouv3EtGn4DTtf8tZsic+0IMfB5n1rgbdbch2JFZwChV PhKaCyufAOZo07XJQFDUpZSQZQnhdDg= X-Google-Smtp-Source: AA6agR4NFI0cuDVESxlL2yTJ6/uQW9iYiv+z7kIkPwRDzL4b++BiOq2ScsKvPCiuhth7zyBYZ7lBZw== X-Received: by 2002:a05:600c:4fcf:b0:3a3:40f6:4c4d with SMTP id o15-20020a05600c4fcf00b003a340f64c4dmr17728158wmq.60.1659985676345; Mon, 08 Aug 2022 12:07:56 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id ay32-20020a05600c1e2000b003a2e7c13a3asm14947316wmb.42.2022.08.08.12.07.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 Aug 2022 12:07:55 -0700 (PDT) Message-Id: <55c77ba4b291fffe3031fbef67dcee9aa91a105c.1659985672.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Mon, 08 Aug 2022 19:07:50 +0000 Subject: [PATCH v3 2/4] oneway_diff: handle removed sparse directories Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: derrickstolee@github.com, shaoxuan.yuan02@gmail.com, newren@gmail.com, gitster@pobox.com, Victoria Dye , Victoria Dye Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Victoria Dye From: Victoria Dye Update 'do_oneway_diff()' to perform a 'diff_tree_oid()' on removed sparse directories, as it does for added or modified sparse directories (see 9eb00af562 (diff-lib: handle index diffs with sparse dirs, 2021-07-14)). At the moment, this update is unreachable code because 'unpack_trees()' (currently the only way 'oneway_diff()' can be called, via 'diff_cache()') will always traverse trees down to the individual removed files of a deleted sparse directory. A subsequent patch will change this to better preserve a sparse index in other uses of 'unpack_tree()', e.g. 'git reset --hard'. However, making that change without this patch would result in (among other issues) 'git status' printing only the name of a deleted sparse directory, not its contents. To avoid introducing that bug, 'do_oneway_diff()' is updated before modifying 'unpack_trees()'. Signed-off-by: Victoria Dye --- diff-lib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/diff-lib.c b/diff-lib.c index 7eb66a417aa..2edea41a234 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -466,6 +466,11 @@ static void do_oneway_diff(struct unpack_trees_options *o, * Something removed from the tree? */ if (!idx) { + if (S_ISSPARSEDIR(tree->ce_mode)) { + diff_tree_oid(&tree->oid, NULL, tree->name, &revs->diffopt); + return; + } + diff_index_show_file(revs, "-", tree, &tree->oid, 1, tree->ce_mode, 0); return; From patchwork Mon Aug 8 19:07:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victoria Dye X-Patchwork-Id: 12939020 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5EB8C25B0C for ; Mon, 8 Aug 2022 19:08:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244258AbiHHTIM (ORCPT ); Mon, 8 Aug 2022 15:08:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58828 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244245AbiHHTIA (ORCPT ); Mon, 8 Aug 2022 15:08:00 -0400 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 65F9E193DB for ; Mon, 8 Aug 2022 12:07:59 -0700 (PDT) Received: by mail-wr1-x42c.google.com with SMTP id v3so11989572wrp.0 for ; Mon, 08 Aug 2022 12:07:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc; bh=maZOsFc1adNGFOL7zMXtYbI5Uef7oOKBFPZA/0sIaBo=; b=FpwOVfeSIpCJPloVSezJMz2tn3vZ2oFy8JMoAWbl+d2Qgwbca8ZBGr2JunM0Wfr0hN z75RsuDCpm875RMnJCspd0CyDhD6YEzvzOdTgMWQ5udU2klE9DUWcNmBwnrilhgH2aXA 7SP3sPPHYPoa/QO8VBq91ycwwyBPA0KOT4GCSp5VTI2tAZ7NsInVjqM0BkSdUVIgxdBg wQNHtf/EPunF7xMYlYFY6XXXBh4zDB88cKg0Oea6fADEoeQnTB6zVngiC4dq6hXygMl6 +9+pKbHtBAgmzUyHsz4zUw1x7hnfYERpN+HccMh4H7eV+zy4fRJTOiOij5ajG9qhAYfH S1og== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc; bh=maZOsFc1adNGFOL7zMXtYbI5Uef7oOKBFPZA/0sIaBo=; b=ieRdbWClWEWfm6M/PikWbFNmCW4EOu1bIp521N2kvj5p+4SJSWzGhfyqA+YX6dPpcn 49X6KgnUut4oSau5kJKSgYNtTxNadMkrlo+W/Y6FkDTfM+j9WcMuEiaRyn4FVzI9TWRa +GBp2DzhuYg+TYP7cU1a7gjwueE7fydvaIVeDoX6J/BWvV8JvEeOohxNgImvaMd5WUZg 864wOX4JTvuYEsfQu7HCSSDOC2CZYGpi7u+rvw/t6KAXLPqt/4ZFDkRXG/adXgn+NPvK qaLjdmiGXBFNbUUJXWDbEn4oKcPVyuve5d0m50GYxjHM+2A40gcWlTYm097WnryB01zY mkXA== X-Gm-Message-State: ACgBeo3PQVlRHfPnLqyy5PQMSnBmMKLW2kVpYcSOjeasSefFHO1dSkez QPjD082Zj7cWZEIcFKYYEzPFwqzN4lM= X-Google-Smtp-Source: AA6agR65kgEZ1D0FrOSDV0ihi6dSPnUu7PH8tYbBc4LaEV/8MZht5H8Z05FC7AWDws6GW9771TpOxg== X-Received: by 2002:adf:db8e:0:b0:21e:3fff:6bae with SMTP id u14-20020adfdb8e000000b0021e3fff6baemr11652843wri.184.1659985677443; Mon, 08 Aug 2022 12:07:57 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id w8-20020a5d6088000000b002185631adf0sm11879261wrt.23.2022.08.08.12.07.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 Aug 2022 12:07:56 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Mon, 08 Aug 2022 19:07:51 +0000 Subject: [PATCH v3 3/4] cache.h: create 'index_name_pos_sparse()' Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: derrickstolee@github.com, shaoxuan.yuan02@gmail.com, newren@gmail.com, gitster@pobox.com, Victoria Dye , Victoria Dye Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Victoria Dye From: Victoria Dye Add 'index_name_pos_sparse()', which behaves the same as 'index_name_pos()', except that it does not expand a sparse index to search for an entry inside a sparse directory. 'index_entry_exists()' was originally implemented in 20ec2d034c (reset: make sparse-aware (except --mixed), 2021-11-29) as an alternative to 'index_name_pos()' to allow callers to search for an index entry without expanding a sparse index. However, that particular use case only required knowing whether the requested entry existed, so 'index_entry_exists()' does not return the index positioning information provided by 'index_name_pos()'. This patch implements 'index_name_pos_sparse()' to accommodate callers that need the positioning information of 'index_name_pos()', but do not want to expand the index. Signed-off-by: Victoria Dye --- cache.h | 9 +++++++++ read-cache.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/cache.h b/cache.h index 4aa1bd079d5..4fa3be26393 100644 --- a/cache.h +++ b/cache.h @@ -830,6 +830,15 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na */ int index_name_pos(struct index_state *, const char *name, int namelen); +/* + * Like index_name_pos, returns the position of an entry of the given name in + * the index if one exists, otherwise returns a negative value where the negated + * value minus 1 is the position where the index entry would be inserted. Unlike + * index_name_pos, however, a sparse index is not expanded to find an entry + * inside a sparse directory. + */ +int index_name_pos_sparse(struct index_state *, const char *name, int namelen); + /* * Determines whether an entry with the given name exists within the * given index. The return value is 1 if an exact match is found, otherwise diff --git a/read-cache.c b/read-cache.c index 4de207752dc..b09128b1884 100644 --- a/read-cache.c +++ b/read-cache.c @@ -620,6 +620,11 @@ int index_name_pos(struct index_state *istate, const char *name, int namelen) return index_name_stage_pos(istate, name, namelen, 0, EXPAND_SPARSE); } +int index_name_pos_sparse(struct index_state *istate, const char *name, int namelen) +{ + return index_name_stage_pos(istate, name, namelen, 0, NO_EXPAND_SPARSE); +} + int index_entry_exists(struct index_state *istate, const char *name, int namelen) { return index_name_stage_pos(istate, name, namelen, 0, NO_EXPAND_SPARSE) >= 0; From patchwork Mon Aug 8 19:07:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Victoria Dye X-Patchwork-Id: 12939021 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A6779C25B08 for ; Mon, 8 Aug 2022 19:08:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244267AbiHHTIO (ORCPT ); Mon, 8 Aug 2022 15:08:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238225AbiHHTIC (ORCPT ); Mon, 8 Aug 2022 15:08:02 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BE5C193F7 for ; Mon, 8 Aug 2022 12:08:00 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id a11so5242127wmq.3 for ; Mon, 08 Aug 2022 12:08:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc; bh=2u8CcRF4Z7axc+JNvIlGvWV5aPCC/5ShJgcJ/COMXgM=; b=KTOz8NgioZR/jQb07CbklPS2r6TVB7YnrECoWbPqJnvFNKEBkrOfH2RU9a+/omRO7a Sm2T0Jr1uqcydpPJ+aP6qxlRxGg4wlNYA/IaZMwSsdIyUaaq6vpjQ7xYc1Ebonkykirh byUhg1wAheuU0YCaY5VROrZWXmdY2Bt46+9+sYULR7nGs83D0CjC4PrlTNYY3lVr3Zv8 EhzdyP33Ms2n+KR7Qrr44J2TvoaQ8iibDgUSQhAhPI+/dPLIov9Wl/vZ3O0jTGrdZ/N/ fVsNQsbShMu2CAruIHmNnaM0grhKBShvFuqn3VEL/4cKlfXbL/8ZGIiC61HLdatwJWiX 0gvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc; bh=2u8CcRF4Z7axc+JNvIlGvWV5aPCC/5ShJgcJ/COMXgM=; b=Iuj4y1G3v8bwKcugdtKpNcTTHfw/rkdvDd44xyKIaT8ULu3lgjlY/8pzRbdFbFg21H WskSIYeuggMGtLyia/U7NbXeQhLrGyq+lNnIZuKJhSTlY38JHPh0gOR88u0EiFbZDZML 8a5KDAWv2citP7BUpLDXte/eztddqcYD8g6Sdf2VWGskaetqQlIJL/+ueJ/N2bLMvWSP /Y146isbIJ1uFxcxqzMANjVacE/+xb5jA5bZw9X8pQnp+1WjJbKewyGZKAEBlBZJXNxA LnqNrdp/Y2uAHz4L+l6Lq17uaSeC05DX8QQZaI96hsYHaX98teL/9DtWLRmOghGJmzm6 8OeQ== X-Gm-Message-State: ACgBeo3pQJ8XxEgjeFZA1VyPs+yLKn+v6zwKYdpA8Br1fAknHanmhHaI Ss+DWjLH0LPzSnOO/pZ++vyxMzGSZAg= X-Google-Smtp-Source: AA6agR7um7wHwYJtKTG0hEpcOAfsFll3Oyoqg3fffZO+YcIi0CafW8g5yYg3LEV1WbBq56Ed/VfRaA== X-Received: by 2002:a1c:ed05:0:b0:3a5:3af:f5c3 with SMTP id l5-20020a1ced05000000b003a503aff5c3mr13619608wmh.52.1659985678555; Mon, 08 Aug 2022 12:07:58 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 11-20020a05600c240b00b003a331c6bffdsm14767461wmp.47.2022.08.08.12.07.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 Aug 2022 12:07:57 -0700 (PDT) Message-Id: <010d5e51595bd3f77b6d3606298a2b436c66ecc6.1659985672.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Mon, 08 Aug 2022 19:07:52 +0000 Subject: [PATCH v3 4/4] unpack-trees: unpack new trees as sparse directories Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: derrickstolee@github.com, shaoxuan.yuan02@gmail.com, newren@gmail.com, gitster@pobox.com, Victoria Dye , Victoria Dye Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Victoria Dye From: Victoria Dye If 'unpack_single_entry()' is unpacking a new directory tree (that is, one not already present in the index) into a sparse index, unpack the tree as a sparse directory rather than traversing its contents and unpacking each file individually. This helps keep the sparse index as collapsed as possible in cases such as 'git reset --hard' restoring a outside-of-cone directory removed with 'git rm -r --sparse'. Without this patch, 'unpack_single_entry()' will only unpack a directory into the index as a sparse directory (rather than traversing into it and unpacking its files one-by-one) if an entry with the same name already exists in the index. This patch allows sparse directory unpacking without a matching index entry when the following conditions are met: 1. the directory's path is outside the sparse cone, and 2. there are no children of the directory in the index If a directory meets these requirements (as determined by 'is_new_sparse_dir()'), 'unpack_single_entry()' unpacks the sparse directory index entry and propagates the decision back up to 'unpack_callback()' to prevent unnecessary tree traversal into the unpacked directory. Reported-by: Shaoxuan Yuan Signed-off-by: Victoria Dye --- t/t1092-sparse-checkout-compatibility.sh | 17 ++++ unpack-trees.c | 106 ++++++++++++++++++++--- 2 files changed, 113 insertions(+), 10 deletions(-) diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 99a1425a929..3588dd7b102 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -695,6 +695,23 @@ test_expect_success 'reset with wildcard pathspec' ' test_all_match git ls-files -s -- folder1 ' +test_expect_success 'reset hard with removed sparse dir' ' + init_repos && + + run_on_all git rm -r --sparse folder1 && + test_all_match git status --porcelain=v2 && + + test_all_match git reset --hard && + test_all_match git status --porcelain=v2 && + + cat >expect <<-\EOF && + folder1/ + EOF + + git -C sparse-index ls-files --sparse folder1 >out && + test_cmp expect out +' + test_expect_success 'update-index modify outside sparse definition' ' init_repos && diff --git a/unpack-trees.c b/unpack-trees.c index 8a454e03bff..90b92114be8 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1069,6 +1069,67 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, return ce; } +/* + * Determine whether the path specified by 'p' should be unpacked as a new + * sparse directory in a sparse index. A new sparse directory 'A/': + * - must be outside the sparse cone. + * - must not already be in the index (i.e., no index entry with name 'A/' + * exists). + * - must not have any child entries in the index (i.e., no index entry + * 'A/' exists). + * If 'p' meets the above requirements, return 1; otherwise, return 0. + */ +static int entry_is_new_sparse_dir(const struct traverse_info *info, + const struct name_entry *p) +{ + int res, pos; + struct strbuf dirpath = STRBUF_INIT; + struct unpack_trees_options *o = info->data; + + if (!S_ISDIR(p->mode)) + return 0; + + /* + * If the path is inside the sparse cone, it can't be a sparse directory. + */ + strbuf_add(&dirpath, info->traverse_path, info->pathlen); + strbuf_add(&dirpath, p->path, p->pathlen); + strbuf_addch(&dirpath, '/'); + if (path_in_cone_mode_sparse_checkout(dirpath.buf, o->src_index)) { + res = 0; + goto cleanup; + } + + pos = index_name_pos_sparse(o->src_index, dirpath.buf, dirpath.len); + if (pos >= 0) { + /* Path is already in the index, not a new sparse dir */ + res = 0; + goto cleanup; + } + + /* Where would this sparse dir be inserted into the index? */ + pos = -pos - 1; + if (pos >= o->src_index->cache_nr) { + /* + * Sparse dir would be inserted at the end of the index, so we + * know it has no child entries. + */ + res = 1; + goto cleanup; + } + + /* + * If the dir has child entries in the index, the first would be at the + * position the sparse directory would be inserted. If the entry at this + * position is inside the dir, not a new sparse dir. + */ + res = strncmp(o->src_index->cache[pos]->name, dirpath.buf, dirpath.len); + +cleanup: + strbuf_release(&dirpath); + return res; +} + /* * Note that traverse_by_cache_tree() duplicates some logic in this function * without actually calling it. If you change the logic here you may need to @@ -1078,21 +1139,44 @@ static int unpack_single_entry(int n, unsigned long mask, unsigned long dirmask, struct cache_entry **src, const struct name_entry *names, - const struct traverse_info *info) + const struct traverse_info *info, + int *is_new_sparse_dir) { int i; struct unpack_trees_options *o = info->data; unsigned long conflicts = info->df_conflicts | dirmask; + const struct name_entry *p = names; - if (mask == dirmask && !src[0]) - return 0; + *is_new_sparse_dir = 0; + if (mask == dirmask && !src[0]) { + /* + * If we're not in a sparse index, we can't unpack a directory + * without recursing into it, so we return. + */ + if (!o->src_index->sparse_index) + return 0; + + /* Find first entry with a real name (we could use "mask" too) */ + while (!p->mode) + p++; + + /* + * If the directory is completely missing from the index but + * would otherwise be a sparse directory, we should unpack it. + * If not, we'll return and continue recursively traversing the + * tree. + */ + *is_new_sparse_dir = entry_is_new_sparse_dir(info, p); + if (!*is_new_sparse_dir) + return 0; + } /* - * When we have a sparse directory entry for src[0], - * then this isn't necessarily a directory-file conflict. + * When we are unpacking a sparse directory, then this isn't necessarily + * a directory-file conflict. */ - if (mask == dirmask && src[0] && - S_ISSPARSEDIR(src[0]->ce_mode)) + if (mask == dirmask && + (*is_new_sparse_dir || (src[0] && S_ISSPARSEDIR(src[0]->ce_mode)))) conflicts = 0; /* @@ -1352,7 +1436,7 @@ static int unpack_sparse_callback(int n, unsigned long mask, unsigned long dirma { struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; struct unpack_trees_options *o = info->data; - int ret; + int ret, is_new_sparse_dir; assert(o->merge); @@ -1376,7 +1460,7 @@ static int unpack_sparse_callback(int n, unsigned long mask, unsigned long dirma * "index" tree (i.e., names[0]) and adjust 'names', 'n', 'mask', and * 'dirmask' accordingly. */ - ret = unpack_single_entry(n - 1, mask >> 1, dirmask >> 1, src, names + 1, info); + ret = unpack_single_entry(n - 1, mask >> 1, dirmask >> 1, src, names + 1, info, &is_new_sparse_dir); if (src[0]) discard_cache_entry(src[0]); @@ -1394,6 +1478,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; struct unpack_trees_options *o = info->data; const struct name_entry *p = names; + int is_new_sparse_dir; /* Find first entry with a real name (we could use "mask" too) */ while (!p->mode) @@ -1440,7 +1525,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str } } - if (unpack_single_entry(n, mask, dirmask, src, names, info) < 0) + if (unpack_single_entry(n, mask, dirmask, src, names, info, &is_new_sparse_dir)) return -1; if (o->merge && src[0]) { @@ -1478,6 +1563,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str } if (!is_sparse_directory_entry(src[0], names, info) && + !is_new_sparse_dir && traverse_trees_recursive(n, dirmask, mask & ~dirmask, names, info) < 0) { return -1;