From patchwork Sun May 10 00:41:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matheus Tavares X-Patchwork-Id: 11538593 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 18D14139A for ; Sun, 10 May 2020 00:42:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F346620746 for ; Sun, 10 May 2020 00:42:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=usp-br.20150623.gappssmtp.com header.i=@usp-br.20150623.gappssmtp.com header.b="ClQTdxnl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728924AbgEJAmC (ORCPT ); Sat, 9 May 2020 20:42:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726778AbgEJAmA (ORCPT ); Sat, 9 May 2020 20:42:00 -0400 Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9B966C061A0C for ; Sat, 9 May 2020 17:42:00 -0700 (PDT) Received: by mail-qk1-x744.google.com with SMTP id b6so4931128qkh.11 for ; Sat, 09 May 2020 17:42:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=usp-br.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gUU3kG2njJdwu6kxo7ucxWl6Z9P+M9pcu/vz3EAnCTc=; b=ClQTdxnliutVXQ4Glow/loeGohDv8BhX816LxUjBabh9J1gMq1YR3E5TNCrutG4QCN YE3EttmQGYn89WrC6kZ+rMB5GC4m+4QNxqH6kjqteeOa5zjuu+A7QGQuVdcKwxMOLwo/ 3p6T9gFUQ9D4Lqfm1qy6Iqcn9MNRdpmJ4JZ3/ZxGraAc73H0SyGGrTE0cqj1V8Tpsh/O fYUFYB703T5A1qcZ+UB89kJmKCl3CbDr4Cjg8YAbJQk5X9XCgY8UVtuw429J5tiRcCyn w0CgeRGOyPxxXVuXooADSsiWsubkvJ7+XzaTlZSga4aK7cFLO8fc+7K6rYmaUmyCXq7r ZzPw== 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=gUU3kG2njJdwu6kxo7ucxWl6Z9P+M9pcu/vz3EAnCTc=; b=PIT4d1lEj0eusw0oPCj0Wnx7QIw0zrw6psa9dyGtXA9ipqBXaEKSmgbmLxjh6cC9NX 4bfxdoIkotLadqt/Lr6Gvoc+oKd7jO3gkZ1iTPsAT92WJA5ZlLvrqfa6elVLI8kKwmRF IOvg0EKr0XsX/2drIn5bndaZu+TiYRVYxUPVQxZQgu3xp8L7xTlTHoyiP18ar+ydjcsD NKaH+IOX5ZYhkSlXeYDKL7n6RHaWqkFb63iDqY9/y3YKIcC7pjEFXdANW9b9QR46nwfr 92450zG8WjSy8ihvCY5JavgImb0T56y7eje87zZ96wQZFote0Kd39LP475Nco/YXKHVF mI+A== X-Gm-Message-State: AGi0PuZcpg4Dvd15IUu8dHrsy2DmEfSrAHoVSHa/E3lGF2AfZkCFzxLS DuqW//LbU2FOYQ+kqcm0i8llu803WP8= X-Google-Smtp-Source: APiQypLv6fmrwXv5qvLgo9kjNPxDrXCu2yVq9Hw2+88zrpuanxu6tP/C82bmRx1ol5uZ23g+4WCCbg== X-Received: by 2002:a37:9d4f:: with SMTP id g76mr264872qke.235.1589071319389; Sat, 09 May 2020 17:41:59 -0700 (PDT) Received: from mango.spo.virtua.com.br ([2804:14c:81:9a16::1]) by smtp.gmail.com with ESMTPSA id s8sm5615974qtb.0.2020.05.09.17.41.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 May 2020 17:41:58 -0700 (PDT) From: Matheus Tavares To: git@vger.kernel.org Cc: gitster@pobox.com, stolee@gmail.com, newren@gmail.com, jonathantanmy@google.com Subject: [RFC PATCH v2 1/4] doc: grep: unify info on configuration variables Date: Sat, 9 May 2020 21:41:27 -0300 Message-Id: X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Explanations about the configuration variables for git-grep are duplicated in "Documentation/git-grep.txt" and "Documentation/config/grep.txt", which can make maintenance difficult. The first also contains a definition not present in the latter (grep.fullName). To avoid problems like this, let's unify the information in the second file and include it in the first. Signed-off-by: Matheus Tavares --- Documentation/config/grep.txt | 10 ++++++++-- Documentation/git-grep.txt | 36 ++++++----------------------------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt index 44abe45a7c..dd51db38e1 100644 --- a/Documentation/config/grep.txt +++ b/Documentation/config/grep.txt @@ -16,8 +16,14 @@ grep.extendedRegexp:: other than 'default'. grep.threads:: - Number of grep worker threads to use. - See `grep.threads` in linkgit:git-grep[1] for more information. + Number of grep worker threads to use. See `--threads` +ifndef::git-grep[] + in linkgit:git-grep[1] +endif::git-grep[] + for more information. + +grep.fullName:: + If set to true, enable `--full-name` option by default. grep.fallbackToNoIndex:: If set to true, fall back to git grep --no-index if git grep diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index a7f9bc99ea..9bdf807584 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -41,34 +41,8 @@ characters. An empty string as search expression matches all lines. CONFIGURATION ------------- -grep.lineNumber:: - If set to true, enable `-n` option by default. - -grep.column:: - If set to true, enable the `--column` option by default. - -grep.patternType:: - Set the default matching behavior. Using a value of 'basic', 'extended', - 'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`, - `--fixed-strings`, or `--perl-regexp` option accordingly, while the - value 'default' will return to the default matching behavior. - -grep.extendedRegexp:: - If set to true, enable `--extended-regexp` option by default. This - option is ignored when the `grep.patternType` option is set to a value - other than 'default'. - -grep.threads:: - Number of grep worker threads to use. If unset (or set to 0), Git will - use as many threads as the number of logical cores available. - -grep.fullName:: - If set to true, enable `--full-name` option by default. - -grep.fallbackToNoIndex:: - If set to true, fall back to git grep --no-index if git grep - is executed outside of a git repository. Defaults to false. - +:git-grep: 1 +include::config/grep.txt[] OPTIONS ------- @@ -269,8 +243,10 @@ providing this option will cause it to die. found. --threads :: - Number of grep worker threads to use. - See `grep.threads` in 'CONFIGURATION' for more information. + Number of grep worker threads to use. If not provided (or set to + 0), Git will use as many worker threads as the number of logical + cores available. The default value can also be set with the + `grep.threads` configuration. -f :: Read patterns from , one per line. From patchwork Sun May 10 00:41:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matheus Tavares X-Patchwork-Id: 11538595 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 BE1A31668 for ; Sun, 10 May 2020 00:42:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A7A8A217BA for ; Sun, 10 May 2020 00:42:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=usp-br.20150623.gappssmtp.com header.i=@usp-br.20150623.gappssmtp.com header.b="sQuMNPeq" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728936AbgEJAmD (ORCPT ); Sat, 9 May 2020 20:42:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56142 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728932AbgEJAmD (ORCPT ); Sat, 9 May 2020 20:42:03 -0400 Received: from mail-qv1-xf43.google.com (mail-qv1-xf43.google.com [IPv6:2607:f8b0:4864:20::f43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D3E7C061A0C for ; Sat, 9 May 2020 17:42:03 -0700 (PDT) Received: by mail-qv1-xf43.google.com with SMTP id fb4so2658530qvb.7 for ; Sat, 09 May 2020 17:42:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=usp-br.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=O1u5R8ggOzlkUTvyNzWaw6inkG2dnrZ9hao4+t/gpAQ=; b=sQuMNPeqkRd8srMkhGIRuS7zcB8x7rz0BVK5xxDmfnpu58T6EvVhwjRk4f/oHaDnPB OvnyqoqkFwGR2rCiGLat4ZbGXpMKfGmB6PqXwLxPL2loWcJq+TSY+RvirOV5x7nz1mNu 4lnIDmZGU17awOEKR4B3IFVlcodZfTJRc9Z/pxlUnUNHUhyyklfGq4k4Q1eALZg36Tzg dOD3xskzyVlEGMmxrQfXebTWqlVwbWZos0MBb+Rlb6VE9tdR/9s8ZvThaGkMjfwcT4Fu TO1o4cfBqcbY12vyrSUCHuWblmA64/Uz4sYQQ2TSgHZCFkV9RHMpynczOcw2qB8ZF+n9 s/ug== 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=O1u5R8ggOzlkUTvyNzWaw6inkG2dnrZ9hao4+t/gpAQ=; b=Tv5DfwAWz1VwQOoASLv4Z9pKzqrivMSCqJBgWUi7cl0JkPL0MR0xFMn1WBB8O+pA/u 0ruNnew6ondpqIBMsuBmPSZNzzuQ5ZwM0KC3pG0sI4cTNM64vkMQvHBc4wNs2hsTlXNr Xb1viLsL1gcMSBtAyHlnwgyagrWEPgoE8N5Sy2idAr/o1EdW9xcitCqoinPUR5xNTQcp pW/npqZXTFbJn1hO0J6JX2p9lPxVdwbDFvLT++Xz50i0XAIrjTAmpe6QP74+xsGv1mRh 830+UdNtnMQSlou5/ESnBs7tjtq4PGajIcCgp7RMMTWqC59O8aBwhgWZL5364hRykmDH WH0Q== X-Gm-Message-State: AGi0Pub3zZaoIy1O3USUqzRbzFuVyFzWEuGrVn/h1qEy6ls6Fr8bE+lW KY94YRdfYxAt7M48tHdcP9M2iCzWWRM= X-Google-Smtp-Source: APiQypIVeTxWvPbi3+6iwtc40gpVwJgP3EaBpJzF7qGSzP3M1utZi7ryR/iKIsf1kTZzez7aVCL31A== X-Received: by 2002:ad4:4a27:: with SMTP id n7mr9710028qvz.80.1589071321834; Sat, 09 May 2020 17:42:01 -0700 (PDT) Received: from mango.spo.virtua.com.br ([2804:14c:81:9a16::1]) by smtp.gmail.com with ESMTPSA id s8sm5615974qtb.0.2020.05.09.17.41.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 May 2020 17:42:01 -0700 (PDT) From: Matheus Tavares To: git@vger.kernel.org Cc: gitster@pobox.com, stolee@gmail.com, newren@gmail.com, jonathantanmy@google.com Subject: [RFC PATCH v2 2/4] config: load the correct config.worktree file Date: Sat, 9 May 2020 21:41:28 -0300 Message-Id: <882310b69fd3df0acc6823a2c73bbe1801d9f6c4.1589058209.git.matheus.bernardino@usp.br> X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org One of the steps in do_git_config_sequence() is to load the worktree-specific config file. Although the function receives a git_dir string, it relies on git_pathdup(), which uses the_repository->git_dir, to make the path to the file. Thus, when a submodule has a worktree setting, a command executed in the superproject that recurses into the submodule won't find the said setting. Such a scenario might not be needed now, but it will be in the following patch. git-grep will learn to honor sparse checkouts and, when running with --recurse-submodules, the submodule's sparse checkout settings must be loaded. As these settings are stored in the config.worktree file, they would be ignored without this patch. The fix is simple, we replace git_pathdup() with mkpathdup(), to format the path with the given git_dir. This is the same idea used to make the config.worktree path in setup.c:check_repository_format_gently(). Signed-off-by: Matheus Tavares --- config.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index 8db9c77098..a3d0a0d266 100644 --- a/config.c +++ b/config.c @@ -1747,8 +1747,9 @@ static int do_git_config_sequence(const struct config_options *opts, ret += git_config_from_file(fn, repo_config, data); current_parsing_scope = CONFIG_SCOPE_WORKTREE; - if (!opts->ignore_worktree && repository_format_worktree_config) { - char *path = git_pathdup("config.worktree"); + if (!opts->ignore_worktree && repository_format_worktree_config && + opts->git_dir) { + char *path = mkpathdup("%s/config.worktree", opts->git_dir); if (!access_or_die(path, R_OK, 0)) ret += git_config_from_file(fn, path, data); free(path); From patchwork Sun May 10 00:41:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matheus Tavares X-Patchwork-Id: 11538599 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 95F80139A for ; Sun, 10 May 2020 00:42:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 77A9A21775 for ; Sun, 10 May 2020 00:42:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=usp-br.20150623.gappssmtp.com header.i=@usp-br.20150623.gappssmtp.com header.b="bBU9PU67" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728942AbgEJAmG (ORCPT ); Sat, 9 May 2020 20:42:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56148 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728932AbgEJAmG (ORCPT ); Sat, 9 May 2020 20:42:06 -0400 Received: from mail-qt1-x843.google.com (mail-qt1-x843.google.com [IPv6:2607:f8b0:4864:20::843]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4040C061A0C for ; Sat, 9 May 2020 17:42:05 -0700 (PDT) Received: by mail-qt1-x843.google.com with SMTP id l1so1423620qtp.6 for ; Sat, 09 May 2020 17:42:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=usp-br.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=I+hzfjvL+iL2EzVuTRYQ0o3m0a05TU6kj0w2O8hl6Fw=; b=bBU9PU67yujvLo8waqgH0mdiV1Yt6B7kM1vwJR2AXf7h4asoifBmsufnFB+PdwVoCh /mFrY4TI3Zc0qY9ufunzE0pdnSc7tqDTI7udGMHMsYUj5zMgiHFu2c0L7NvCHPKlXO+5 SO2kOpCc2jGJNUu0jykx1F11QVMfKHf5GV5E3i6I9V4e1RFPcjZB2MKnCf82DVBc7hD2 JyU1wydW/UynxOwFBdnEe/NQbK0BaWP9Jk6LutDbrWAcFTKm8UoTf0VV7WhuzZW+BWyL +KHR1cXqlzipaZ6deIEaQBO9IbsznPli2UMO2m+avbvIu5zG6HNDhLtwC/I25QprNDNY szTg== 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=I+hzfjvL+iL2EzVuTRYQ0o3m0a05TU6kj0w2O8hl6Fw=; b=qIWS9YJKgnuN+cdfuO2cmiJLhxsHiY1HchckqDNZB7F4Ub8Bxuz9RK/VA1xpLzeSm9 7j0BJi8plpLJSBNzYzmQsQrnXkdrEmsYcg7fz38yQwLMq74Ya8N4UgLfi67Xj3vHkKs2 nAr7zPvitmoeUzIw1PcujN3XjCPxkaKaQxRTIWAEKPHEzvX5sVKLhEEZMzBA7qzVAi8d fe3Bj9u13uwEFhVE0bGX2Xl28MPfLDsG9d1LLqYwr+cAyZ47UDWecui0TvuV8uKTINMQ XNLaJm0qZaJnwhn0SEChTCGxy7F1HesHSEu8AHwxbOhRxFy0fvIZRm4ZTPZOdfGkWPqc mj4A== X-Gm-Message-State: AGi0PuYL7QYxWOF/lKrJJFKiaY3DVo/oxDG+FvPUDMSJjSMMNiF1PtzS RId1max6YXvcHQJSnGnV9dP55Uv0EzQ= X-Google-Smtp-Source: APiQypITp6BBWgAEVjEbnFEvMIsiye6NtzQHrtr3YcgIdd4eQwmYwUYN4xRCXpZL0ohcEEqqSDmiXw== X-Received: by 2002:ac8:3f5d:: with SMTP id w29mr8254701qtk.192.1589071324319; Sat, 09 May 2020 17:42:04 -0700 (PDT) Received: from mango.spo.virtua.com.br ([2804:14c:81:9a16::1]) by smtp.gmail.com with ESMTPSA id s8sm5615974qtb.0.2020.05.09.17.42.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 May 2020 17:42:03 -0700 (PDT) From: Matheus Tavares To: git@vger.kernel.org Cc: gitster@pobox.com, stolee@gmail.com, newren@gmail.com, jonathantanmy@google.com Subject: [RFC PATCH v2 3/4] grep: honor sparse checkout patterns Date: Sat, 9 May 2020 21:41:29 -0300 Message-Id: X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org One of the main uses for a sparse checkout is to allow users to focus on the subset of files in a repository in which they are interested. But git-grep currently ignores the sparsity patterns and report all matches found outside this subset, which kind of goes in the opposite direction. Let's fix that, making it honor the sparsity boundaries for every grepping case: - git grep in worktree - git grep --cached - git grep $REVISION - git grep --untracked and git grep --no-index (which already respect sparse checkout boundaries) This is also what some users reported[1] they would want as the default behavior. Note: for `git grep $REVISION`, we will choose to honor the sparsity patterns only when $REVISION is a commit-ish object. The reason is that, for a tree, we don't know whether it represents the root of a repository or a subtree. So we wouldn't be able to correctly match it against the sparsity patterns. E.g. suppose we have a repository with these two sparsity rules: "/*" and "!/a"; and the following structure: / | - a (file) | - d (dir) | - a (file) If `git grep $REVISION` were to honor the sparsity patterns for every object type, when grepping the /d tree, we would wrongly ignore the /d/a file. This happens because we wouldn't know it resides in /d and therefore it would wrongly match the pattern "!/a". Furthermore, for a search in a blob object, we wouldn't even have a path to check the patterns against. So, let's ignore the sparsity patterns when grepping non-commit-ish objects (tags to commits should be fine). Finally, the old behavior may still be desirable for some use cases. So the next patch will add an option to allow restoring it when needed. [1]: https://lore.kernel.org/git/CABPp-BGuFhDwWZBRaD3nA8ui46wor-4=Ha1G1oApsfF8KNpfGQ@mail.gmail.com/ Signed-off-by: Matheus Tavares Signed-off-by: Elijah Newren --- Note: as I mentioned in the cover letter, the tests in this patch now contain both cone mode and full pattern sparse checkouts. This was done for two reasons: To test grep's behavior when searching with --recurse-submodules and having submodules with different pattern sets than the superproject (which was incorrect in my first implementation). And to test the direct pattern matching in grep_tree(), using both modes. builtin/grep.c | 127 ++++++++++++++++++++++++++-- t/t7011-skip-worktree-reading.sh | 9 -- t/t7817-grep-sparse-checkout.sh | 140 +++++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 17 deletions(-) create mode 100755 t/t7817-grep-sparse-checkout.sh diff --git a/builtin/grep.c b/builtin/grep.c index a5056f395a..91ee0b2734 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -410,7 +410,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached); static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len, - int check_attr); + int is_root_tree); static int grep_submodule(struct grep_opt *opt, const struct pathspec *pathspec, @@ -508,6 +508,10 @@ static int grep_cache(struct grep_opt *opt, for (nr = 0; nr < repo->index->cache_nr; nr++) { const struct cache_entry *ce = repo->index->cache[nr]; + + if (ce_skip_worktree(ce) && !S_ISGITLINK(ce->ce_mode)) + continue; + strbuf_setlen(&name, name_base_len); strbuf_addstr(&name, ce->name); @@ -520,8 +524,7 @@ static int grep_cache(struct grep_opt *opt, * cache entry are identical, even if worktree file has * been modified, so use cache version instead */ - if (cached || (ce->ce_flags & CE_VALID) || - ce_skip_worktree(ce)) { + if (cached || (ce->ce_flags & CE_VALID)) { if (ce_stage(ce) || ce_intent_to_add(ce)) continue; hit |= grep_oid(opt, &ce->oid, name.buf, @@ -552,9 +555,78 @@ static int grep_cache(struct grep_opt *opt, return hit; } -static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, - struct tree_desc *tree, struct strbuf *base, int tn_len, - int check_attr) +static struct pattern_list *get_sparsity_patterns(struct repository *repo) +{ + struct pattern_list *patterns; + char *sparse_file; + int sparse_config, cone_config; + + if (repo_config_get_bool(repo, "core.sparsecheckout", &sparse_config) || + !sparse_config) { + return NULL; + } + + sparse_file = repo_git_path(repo, "info/sparse-checkout"); + patterns = xcalloc(1, sizeof(*patterns)); + + if (repo_config_get_bool(repo, "core.sparsecheckoutcone", &cone_config)) + cone_config = 0; + patterns->use_cone_patterns = cone_config; + + if (add_patterns_from_file_to_list(sparse_file, "", 0, patterns, NULL)) { + if (file_exists(sparse_file)) { + warning(_("failed to load sparse-checkout file: '%s'"), + sparse_file); + } + free(sparse_file); + free(patterns); + return NULL; + } + + free(sparse_file); + return patterns; +} + +static int in_sparse_checkout(struct strbuf *path, int prefix_len, + unsigned int entry_mode, + struct index_state *istate, + struct pattern_list *sparsity, + enum pattern_match_result parent_match, + enum pattern_match_result *match) +{ + int dtype = DT_UNKNOWN; + + if (S_ISGITLINK(entry_mode)) + return 1; + + if (parent_match == MATCHED_RECURSIVE) { + *match = parent_match; + return 1; + } + + if (S_ISDIR(entry_mode) && !is_dir_sep(path->buf[path->len - 1])) + strbuf_addch(path, '/'); + + *match = path_matches_pattern_list(path->buf, path->len, + path->buf + prefix_len, &dtype, + sparsity, istate); + if (*match == UNDECIDED) + *match = parent_match; + + if (S_ISDIR(entry_mode)) + strbuf_trim_trailing_dir_sep(path); + + if (*match == NOT_MATCHED && (S_ISREG(entry_mode) || + (S_ISDIR(entry_mode) && sparsity->use_cone_patterns))) + return 0; + + return 1; +} + +static int do_grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, + struct tree_desc *tree, struct strbuf *base, int tn_len, + int check_attr, struct pattern_list *sparsity, + enum pattern_match_result default_sparsity_match) { struct repository *repo = opt->repo; int hit = 0; @@ -570,6 +642,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(&entry); + enum pattern_match_result sparsity_match = 0; if (match != all_entries_interesting) { strbuf_addstr(&name, base->buf + tn_len); @@ -586,6 +659,19 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, strbuf_add(base, entry.path, te_len); + if (sparsity) { + struct strbuf path = STRBUF_INIT; + strbuf_addstr(&path, base->buf + tn_len); + + if (!in_sparse_checkout(&path, old_baselen - tn_len, + entry.mode, repo->index, + sparsity, default_sparsity_match, + &sparsity_match)) { + strbuf_setlen(base, old_baselen); + continue; + } + } + if (S_ISREG(entry.mode)) { hit |= grep_oid(opt, &entry.oid, base->buf, tn_len, check_attr ? base->buf + tn_len : NULL); @@ -602,8 +688,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); - hit |= grep_tree(opt, pathspec, &sub, base, tn_len, - check_attr); + hit |= do_grep_tree(opt, pathspec, &sub, base, tn_len, + check_attr, sparsity, sparsity_match); free(data); } else if (recurse_submodules && S_ISGITLINK(entry.mode)) { hit |= grep_submodule(opt, pathspec, &entry.oid, @@ -621,6 +707,31 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, return hit; } +/* + * Note: sparsity patterns and paths' attributes will only be considered if + * is_root_tree has true value. (Otherwise, we cannot properly perform pattern + * matching on paths.) + */ +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, + struct tree_desc *tree, struct strbuf *base, int tn_len, + int is_root_tree) +{ + struct pattern_list *patterns = NULL; + int ret; + + if (is_root_tree) + patterns = get_sparsity_patterns(opt->repo); + + ret = do_grep_tree(opt, pathspec, tree, base, tn_len, is_root_tree, + patterns, 0); + + if (patterns) { + clear_pattern_list(patterns); + free(patterns); + } + return ret; +} + static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct object *obj, const char *name, const char *path) { diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh index 37525cae3a..26852586ac 100755 --- a/t/t7011-skip-worktree-reading.sh +++ b/t/t7011-skip-worktree-reading.sh @@ -109,15 +109,6 @@ test_expect_success 'ls-files --modified' ' test -z "$(git ls-files -m)" ' -test_expect_success 'grep with skip-worktree file' ' - git update-index --no-skip-worktree 1 && - echo test > 1 && - git update-index 1 && - git update-index --skip-worktree 1 && - rm 1 && - test "$(git grep --no-ext-grep test)" = "1:test" -' - echo ":000000 100644 $ZERO_OID $EMPTY_BLOB A 1" > expected test_expect_success 'diff-index does not examine skip-worktree absent entries' ' setup_absent && diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh new file mode 100755 index 0000000000..3bd67082eb --- /dev/null +++ b/t/t7817-grep-sparse-checkout.sh @@ -0,0 +1,140 @@ +#!/bin/sh + +test_description='grep in sparse checkout + +This test creates a repo with the following structure: + +. +|-- a +|-- b +|-- dir +| `-- c +`-- sub + |-- A + | `-- a + `-- B + `-- b + +Where . has non-cone mode sparsity patterns and sub is a submodule with cone +mode sparsity patterns. The resulting sparse-checkout should leave the following +structure: + +. +|-- a +`-- sub + `-- B + `-- b +' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo "text" >a && + echo "text" >b && + mkdir dir && + echo "text" >dir/c && + + git init sub && + ( + cd sub && + mkdir A B && + echo "text" >A/a && + echo "text" >B/b && + git add A B && + git commit -m sub && + git sparse-checkout init --cone && + git sparse-checkout set B + ) && + + git submodule add ./sub && + git add a b dir && + git commit -m super && + git sparse-checkout init --no-cone && + git sparse-checkout set "/*" "!b" "!/*/" && + + git tag -am t-commit t-commit HEAD && + tree=$(git rev-parse HEAD^{tree}) && + git tag -am t-tree t-tree $tree && + + test_path_is_missing b && + test_path_is_missing dir && + test_path_is_missing sub/A && + test_path_is_file a && + test_path_is_file sub/B/b +' + +test_expect_success 'grep in working tree should honor sparse checkout' ' + cat >expect <<-EOF && + a:text + EOF + git grep "text" >actual && + test_cmp expect actual +' + +test_expect_success 'grep --cached should honor sparse checkout' ' + cat >expect <<-EOF && + a:text + EOF + git grep --cached "text" >actual && + test_cmp expect actual +' + +test_expect_success 'grep should honor sparse checkout' ' + commit=$(git rev-parse HEAD) && + cat >expect_commit <<-EOF && + $commit:a:text + EOF + cat >expect_t-commit <<-EOF && + t-commit:a:text + EOF + git grep "text" $commit >actual_commit && + test_cmp expect_commit actual_commit && + git grep "text" t-commit >actual_t-commit && + test_cmp expect_t-commit actual_t-commit +' + +test_expect_success 'grep should ignore sparsity patterns' ' + commit=$(git rev-parse HEAD) && + tree=$(git rev-parse HEAD^{tree}) && + cat >expect_tree <<-EOF && + $tree:a:text + $tree:b:text + $tree:dir/c:text + EOF + cat >expect_t-tree <<-EOF && + t-tree:a:text + t-tree:b:text + t-tree:dir/c:text + EOF + git grep "text" $tree >actual_tree && + test_cmp expect_tree actual_tree && + git grep "text" t-tree >actual_t-tree && + test_cmp expect_t-tree actual_t-tree +' + +test_expect_success 'grep --recurse-submodules --cached should honor sparse checkout in submodule' ' + cat >expect <<-EOF && + a:text + sub/B/b:text + EOF + git grep --recurse-submodules --cached "text" >actual && + test_cmp expect actual +' + +test_expect_success 'grep --recurse-submodules should honor sparse checkout in submodule' ' + commit=$(git rev-parse HEAD) && + cat >expect_commit <<-EOF && + $commit:a:text + $commit:sub/B/b:text + EOF + cat >expect_t-commit <<-EOF && + t-commit:a:text + t-commit:sub/B/b:text + EOF + git grep --recurse-submodules "text" $commit >actual_commit && + test_cmp expect_commit actual_commit && + git grep --recurse-submodules "text" t-commit >actual_t-commit && + test_cmp expect_t-commit actual_t-commit +' + +test_done From patchwork Sun May 10 00:41:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matheus Tavares X-Patchwork-Id: 11538601 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 EF98B139A for ; Sun, 10 May 2020 00:42:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CBAE120746 for ; Sun, 10 May 2020 00:42:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=usp-br.20150623.gappssmtp.com header.i=@usp-br.20150623.gappssmtp.com header.b="QCK9vg9i" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728948AbgEJAmY (ORCPT ); Sat, 9 May 2020 20:42:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56196 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728932AbgEJAmX (ORCPT ); Sat, 9 May 2020 20:42:23 -0400 Received: from mail-qk1-x742.google.com (mail-qk1-x742.google.com [IPv6:2607:f8b0:4864:20::742]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6FB82C061A0C for ; Sat, 9 May 2020 17:42:23 -0700 (PDT) Received: by mail-qk1-x742.google.com with SMTP id n14so6037086qke.8 for ; Sat, 09 May 2020 17:42:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=usp-br.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=MbUqt6B0oS+ikGLm0xi86meP+iWRcL8tdlJcOtH1rKI=; b=QCK9vg9igkSwH9Hzp8rMjHaiAdG5aMqPI1NN2tM0JIITuQk1ewCvEiLsUU6hqax/jT IkqrbVLq4cDrn3acbB3syYVPZbl0IYGi5wnPwCrsaTs+Io7nwE3yQWMQ6gxgl2WtjJwm B1G7639GbVUCyNccysNxu2DVLwYtEE6irYNnDWadxO5E3MXiS7fhxYQ52GHQcPaCUe5S 7sZxkDf70cgu+vg3U3qYXNf/EkuLhawCdMWFC1vPRcVfYjtWRqbXW3BM/Vjj5q3O6FEC BRz1OepjIMwE6I61X9oRKgWXPejqqfPCNrxkxlfj9D3GmE5H2WRHQ2LvaUw5X1kyDFno qB2Q== 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=MbUqt6B0oS+ikGLm0xi86meP+iWRcL8tdlJcOtH1rKI=; b=Fs4XHQYuqyohXkWCB+loRkW8rs0RZxEdMAEFMIPbe2DSoMxCDcV2TRMDTO2tPzzMiM WPI7tmm5YB9khvt/Nha5OEIzTqafZUAwILaE5cAbc5AReIwiUJio0KPpFPSvg3bkcVrT F7VId/+g0EBzTkYDVTeqkrlWBf879wltZf4Ez2tbusdHlV84YqeALlZViYYkmWPLY/u0 FPJzUmVjITGANgfD0iDn/kA9xzbRET/mszMA1Eaw3lVYkeofPM5a7i6xH0IJ5Cy6+QfV LbFqhXhjxZMkTOnFbOVwt6NIQ0Rd3B7sjZZHiGjfJ+xE1HovQOD+RflPGDf10HRrFETZ rq3w== X-Gm-Message-State: AGi0PuYOAF7syQRqfWAWQLlLcC25L7Ui1dmalN/9DX4f8LHwRyCZ42Mw ln2tAYTmpEdifDMjDxDDlhoHr70HEQ8= X-Google-Smtp-Source: APiQypIDAzS+ApAN8OH/1h1mAxzQ8pOAa2lN+dPQbl9Gd1zqKqmC/zLsxofrRB5qNbvp865/DZ8s8Q== X-Received: by 2002:a37:8045:: with SMTP id b66mr1754717qkd.231.1589071341735; Sat, 09 May 2020 17:42:21 -0700 (PDT) Received: from mango.spo.virtua.com.br ([2804:14c:81:9a16::1]) by smtp.gmail.com with ESMTPSA id s8sm5615974qtb.0.2020.05.09.17.42.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 May 2020 17:42:21 -0700 (PDT) From: Matheus Tavares To: git@vger.kernel.org Cc: gitster@pobox.com, stolee@gmail.com, newren@gmail.com, jonathantanmy@google.com Subject: [RFC PATCH v2 4/4] config: add setting to ignore sparsity patterns in some cmds Date: Sat, 9 May 2020 21:41:30 -0300 Message-Id: <3e9e90624901113fd5c5670c0c2023c709f71d6d.1589058209.git.matheus.bernardino@usp.br> X-Mailer: git-send-email 2.26.2 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When sparse checkout is enabled, some users expect the output of certain commands (such as grep, diff, and log) to be also restricted within the sparsity patterns. This would allow them to effectively work only on the subset of files in which they are interested; and allow some commands to possibly perform better, by not considering uninteresting paths. For this reason, we taught grep to honor the sparsity patterns, in the previous commit. But, on the other hand, allowing grep and the other commands mentioned to optionally ignore the patterns also make for some interesting use cases. E.g. using grep to search for a function definition that resides outside the sparse checkout. In any case, there is no current way for users to configure the behavior they want for these commands. Aiming to provide this flexibility, let's introduce the sparse.restrictCmds setting (and the analogous --[no]-restrict-to-sparse-paths global option). The default value is true. For now, grep is the only one affected by this setting, but the goal is to have support for more commands, in the future. Helped-by: Elijah Newren Signed-off-by: Matheus Tavares --- Some notes/questions about this one: - I guess having the additional sparse-checkout.o only for the restrict_to_sparse_paths() function is not very justifiable. Especially since builtin/grep.c is currently its only caller. But since Stolee is already moving some code out of the sparse-checkout builtin and into sparse-checkout.o [1], I thought it would be better to place this function here from the start, as it will likely be needed by other cmds when they start honoring sparse.restrictCmds. (Side note: I think I will also be able to use the populate_sparse_checkout_patterns() function added by Stolee in the same patchset [2], to avoid code duplication in the get_sparsity_patterns() function added in this patch). [1]: https://lore.kernel.org/git/0181a134bfb6986dc0e54ae624c478446a1324a9.1588857462.git.gitgitgadget@gmail.com/ [2]: https://lore.kernel.org/git/444a6b5f894f28e96f713e5caccba18e1ea3b3eb.1588857462.git.gitgitgadget@gmail.com/ - With that said, the only reason we need restrict_to_sparse_paths() to begin with, is so that commands which recurse into submodules may respect the value set in each submodule for the sparse.restrictCmds config. This is already being done for grep, in this patch. But, should we do like this or should we use the value set at the superproject, for all submodules as well, when recursing (ignoring the value set on them)? - It's possible to also make read-tree respect the new setting/option, using --no-restrict-to-sparse-paths as a synonym for its --no-sparse-checkout option (with lower precedence). However, as this command can change the sparse checked out paths, I thought it kind of falls under a different category. Also, `git read-tree -mu --sparse-checkout` doesn't have the effect of *restricting* the command's behavior to the sparsity patterns, but of applying them to the working tree, right? So maybe it could be confusing to make this command honor the new setting. Does that make sense, or should we do it? - Finally, if we decide to make read-tree be affected by sparse.restrictCmds, there is also the case of whether the config should be honored for submodules or just propagate the superproject's value. I think the latter would be as simple as adding this line, before calling parse_options() in builtin/read-tree.c: opts.skip_sparse_checkout = !restrict_to_sparse_paths(the_repository); As for the former, I'm not very familiar with the code in unpack_trees(), so I'm not sure how complicated that would be. Documentation/config.txt | 2 + Documentation/config/sparse.txt | 22 ++++++++ Documentation/git-grep.txt | 3 + Documentation/git.txt | 4 ++ Makefile | 1 + builtin/grep.c | 14 ++++- contrib/completion/git-completion.bash | 2 + git.c | 6 ++ sparse-checkout.c | 16 ++++++ sparse-checkout.h | 11 ++++ t/t7817-grep-sparse-checkout.sh | 78 +++++++++++++++++++++++++- t/t9902-completion.sh | 4 +- 12 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 Documentation/config/sparse.txt create mode 100644 sparse-checkout.c create mode 100644 sparse-checkout.h diff --git a/Documentation/config.txt b/Documentation/config.txt index ef0768b91a..fd74b80302 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -436,6 +436,8 @@ include::config/sequencer.txt[] include::config/showbranch.txt[] +include::config/sparse.txt[] + include::config/splitindex.txt[] include::config/ssh.txt[] diff --git a/Documentation/config/sparse.txt b/Documentation/config/sparse.txt new file mode 100644 index 0000000000..83a4e0018f --- /dev/null +++ b/Documentation/config/sparse.txt @@ -0,0 +1,22 @@ +sparse.restrictCmds:: + Only meaningful in conjunction with core.sparseCheckout. This option + extends sparse checkouts (which limit which paths are written to the + working tree), so that output and operations are also limited to the + sparsity paths where possible and implemented. The purpose of this + option is to (1) focus output for the user on the portion of the + repository that is of interest to them, and (2) enable potentially + dramatic performance improvements, especially in conjunction with + partial clones. ++ +When this option is true (default), some git commands may limit their behavior +to the paths specified by the sparsity patterns, or to the intersection of +those paths and any (like `*.c) that the user might also specify on the command +line. When false, the affected commands will work on full trees, ignoring the +sparsity patterns. For now, only git-grep honors this setting. In this command, +the restriction becomes relevant in one of these three cases: with --cached; +when a commit-ish is given; when searching a working tree that contains paths +previously excluded by the sparsity patterns. ++ +Note: commands which export, integrity check, or create history will always +operate on full trees (e.g. fast-export, format-patch, fsck, commit, etc.), +unaffected by any sparsity patterns. diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 9bdf807584..abbf100109 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -41,6 +41,9 @@ characters. An empty string as search expression matches all lines. CONFIGURATION ------------- +git-grep honors the sparse.restrictCmds setting. See its definition in +linkgit:git-config[1]. + :git-grep: 1 include::config/grep.txt[] diff --git a/Documentation/git.txt b/Documentation/git.txt index 9d6769e95a..5e107c6246 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -180,6 +180,10 @@ If you just want to run git as if it was started in `` then use Do not perform optional operations that require locks. This is equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`. +--[no-]restrict-to-sparse-paths:: + Overrides the sparse.restrictCmds configuration (see + linkgit:git-config[1]) for this execution. + --list-cmds=group[,group...]:: List commands by group. This is an internal/experimental option and may change or be removed in the future. Supported diff --git a/Makefile b/Makefile index 3d3a39fc19..67580c691b 100644 --- a/Makefile +++ b/Makefile @@ -986,6 +986,7 @@ LIB_OBJS += sha1-name.o LIB_OBJS += shallow.o LIB_OBJS += sideband.o LIB_OBJS += sigchain.o +LIB_OBJS += sparse-checkout.o LIB_OBJS += split-index.o LIB_OBJS += stable-qsort.o LIB_OBJS += strbuf.o diff --git a/builtin/grep.c b/builtin/grep.c index 91ee0b2734..3f92e7fd6c 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -25,6 +25,7 @@ #include "submodule-config.h" #include "object-store.h" #include "packfile.h" +#include "sparse-checkout.h" static char const * const grep_usage[] = { N_("git grep [] [-e] [...] [[--] ...]"), @@ -498,6 +499,7 @@ static int grep_cache(struct grep_opt *opt, int nr; struct strbuf name = STRBUF_INIT; int name_base_len = 0; + int sparse_paths_only = restrict_to_sparse_paths(repo); if (repo->submodule_prefix) { name_base_len = strlen(repo->submodule_prefix); strbuf_addstr(&name, repo->submodule_prefix); @@ -509,7 +511,8 @@ static int grep_cache(struct grep_opt *opt, for (nr = 0; nr < repo->index->cache_nr; nr++) { const struct cache_entry *ce = repo->index->cache[nr]; - if (ce_skip_worktree(ce) && !S_ISGITLINK(ce->ce_mode)) + if (sparse_paths_only && ce_skip_worktree(ce) && + !S_ISGITLINK(ce->ce_mode)) continue; strbuf_setlen(&name, name_base_len); @@ -717,9 +720,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, int is_root_tree) { struct pattern_list *patterns = NULL; + int sparse_paths_only = restrict_to_sparse_paths(opt->repo); int ret; - if (is_root_tree) + if (is_root_tree && sparse_paths_only) patterns = get_sparsity_patterns(opt->repo); ret = do_grep_tree(opt, pathspec, tree, base, tn_len, is_root_tree, @@ -1259,6 +1263,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!use_index || untracked) { int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; + + if (opt_restrict_to_sparse_paths >= 0) { + warning(_("--[no-]restrict-to-sparse-paths is ignored" + " with --no-index or --untracked")); + } + hit = grep_directory(&opt, &pathspec, use_exclude, use_index); } else if (0 <= opt_exclude) { die(_("--[no-]exclude-standard cannot be used for tracked contents")); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index b1d6e5ebed..cba0f9166c 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3207,6 +3207,8 @@ __git_main () --namespace= --no-replace-objects --help + --restrict-to-sparse-paths + --no-restrict-to-sparse-paths " ;; *) diff --git a/git.c b/git.c index 2e4efb4ff0..f967c75d9c 100644 --- a/git.c +++ b/git.c @@ -37,6 +37,7 @@ const char git_more_info_string[] = "See 'git help git' for an overview of the system."); static int use_pager = -1; +int opt_restrict_to_sparse_paths = -1; static void list_builtins(struct string_list *list, unsigned int exclude_option); @@ -310,6 +311,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) } else { exit(list_cmds(cmd)); } + } else if (!strcmp(cmd, "--restrict-to-sparse-paths")) { + opt_restrict_to_sparse_paths = 1; + } else if (!strcmp(cmd, "--no-restrict-to-sparse-paths")) { + opt_restrict_to_sparse_paths = 0; } else { fprintf(stderr, _("unknown option: %s\n"), cmd); usage(git_usage_string); @@ -318,6 +323,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) (*argv)++; (*argc)--; } + return (*argv) - orig_argv; } diff --git a/sparse-checkout.c b/sparse-checkout.c new file mode 100644 index 0000000000..9a9e50fd29 --- /dev/null +++ b/sparse-checkout.c @@ -0,0 +1,16 @@ +#include "cache.h" +#include "config.h" +#include "sparse-checkout.h" + +int restrict_to_sparse_paths(struct repository *repo) +{ + int ret; + + if (opt_restrict_to_sparse_paths >= 0) + return opt_restrict_to_sparse_paths; + + if (repo_config_get_bool(repo, "sparse.restrictcmds", &ret)) + ret = 1; + + return ret; +} diff --git a/sparse-checkout.h b/sparse-checkout.h new file mode 100644 index 0000000000..1de3b588d8 --- /dev/null +++ b/sparse-checkout.h @@ -0,0 +1,11 @@ +#ifndef SPARSE_CHECKOUT_H +#define SPARSE_CHECKOUT_H + +struct repository; + +extern int opt_restrict_to_sparse_paths; /* from git.c */ + +/* Whether or not cmds should restrict behavior on sparse paths, in this repo */ +int restrict_to_sparse_paths(struct repository *repo); + +#endif /* SPARSE_CHECKOUT_H */ diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh index 3bd67082eb..8509694bf1 100755 --- a/t/t7817-grep-sparse-checkout.sh +++ b/t/t7817-grep-sparse-checkout.sh @@ -63,12 +63,28 @@ test_expect_success 'setup' ' test_path_is_file sub/B/b ' +# The two tests bellow check a special case: the sparsity patterns exclude '/b' +# and sparse checkout is enable, but the path exists on the working tree (e.g. +# manually created after `git sparse-checkout init`). In this case, grep should +# honor --restrict-to-sparse-paths. test_expect_success 'grep in working tree should honor sparse checkout' ' cat >expect <<-EOF && a:text EOF + echo newtext >b && git grep "text" >actual && - test_cmp expect actual + test_cmp expect actual && + rm b +' +test_expect_success 'grep w/ --no-restrict-to-sparse-paths for sparsely excluded but present paths' ' + cat >expect <<-EOF && + a:text + b:newtext + EOF + echo newtext >b && + git --no-restrict-to-sparse-paths grep "text" >actual && + test_cmp expect actual && + rm b ' test_expect_success 'grep --cached should honor sparse checkout' ' @@ -137,4 +153,64 @@ test_expect_success 'grep --recurse-submodules should honor sparse test_cmp expect_t-commit actual_t-commit ' +for cmd in 'git --no-restrict-to-sparse-paths grep' \ + 'git -c sparse.restrictCmds=false grep' \ + 'git -c sparse.restrictCmds=true --no-restrict-to-sparse-paths grep' +do + + test_expect_success "$cmd --cached should ignore sparsity patterns" ' + cat >expect <<-EOF && + a:text + b:text + dir/c:text + EOF + $cmd --cached "text" >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd should ignore sparsity patterns" ' + commit=$(git rev-parse HEAD) && + cat >expect_commit <<-EOF && + $commit:a:text + $commit:b:text + $commit:dir/c:text + EOF + cat >expect_t-commit <<-EOF && + t-commit:a:text + t-commit:b:text + t-commit:dir/c:text + EOF + $cmd "text" $commit >actual_commit && + test_cmp expect_commit actual_commit && + $cmd "text" t-commit >actual_t-commit && + test_cmp expect_t-commit actual_t-commit + ' +done + +test_expect_success 'should respect the sparse.restrictCmds values from submodules' ' + cat >expect <<-EOF && + a:text + sub/A/a:text + sub/B/b:text + EOF + git -C sub config sparse.restrictCmds false && + git grep --cached --recurse-submodules "text" >actual && + test_cmp expect actual && + git -C sub config --unset sparse.restrictCmds +' + +test_expect_success 'should propagate --[no]-restrict-to-sparse-paths to submodules' ' + cat >expect <<-EOF && + a:text + b:text + dir/c:text + sub/A/a:text + sub/B/b:text + EOF + git -C sub config sparse.restrictCmds true && + git --no-restrict-to-sparse-paths grep --cached --recurse-submodules "text" >actual && + test_cmp expect actual && + git -C sub config --unset sparse.restrictCmds +' + test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 3c44af6940..a4a7767e06 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1473,6 +1473,8 @@ test_expect_success 'double dash "git" itself' ' --namespace= --no-replace-objects Z --help Z + --restrict-to-sparse-paths Z + --no-restrict-to-sparse-paths Z EOF ' @@ -1515,7 +1517,7 @@ test_expect_success 'general options' ' test_completion "git --nam" "--namespace=" && test_completion "git --bar" "--bare " && test_completion "git --inf" "--info-path " && - test_completion "git --no-r" "--no-replace-objects " + test_completion "git --no-rep" "--no-replace-objects " ' test_expect_success 'general options plus command' '