git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
From: Phillip Wood <phillip.wood123@gmail.com>
To: Git Mailing List <git@vger.kernel.org>, Duy Nguyen <pclouds@gmail.com>
Cc: Junio C Hamano <gitster@pobox.com>,
	Phillip Wood <phillip.wood@dunelm.org.uk>
Subject: [PATCH 2/2] read-tree: add --exclude-standard
Date: Wed,  1 May 2019 11:14:03 +0100	[thread overview]
Message-ID: <20190501101403.20294-3-phillip.wood123@gmail.com> (raw)
In-Reply-To: <20190501101403.20294-1-phillip.wood123@gmail.com>

From: Phillip Wood <phillip.wood@dunelm.org.uk>

Currently there is no way to get read-tree to respect
.git/info/exclude or core.excludesFile so scripts using `read-tree -u`
have subtly different behavior to porcelain commands like checkout
even when they use --exclude-per-directory. This new option is copied
from ls-tree's --exclude-standard option to setup the standard
excludes. The new option is also used to fix a known submodule test
failure.

Note that KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED is still
used by t7112-reset-submodule.sh as it is not removed (apparently
reset does not call setup_standard_excludes()).

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---
 Documentation/git-read-tree.txt |  9 +++++-
 builtin/read-tree.c             | 55 ++++++++++++++++++++++++++++++---
 t/t1005-read-tree-reset.sh      | 36 ++++++++++++++++++---
 t/t1013-read-tree-submodule.sh  |  3 +-
 4 files changed, 90 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 67864c6bbc..a2b8b73a99 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -107,7 +107,14 @@ OPTIONS
 	running `make clean` to remove the generated file.  This
 	option tells the command to read per-directory exclude
 	file (usually '.gitignore') and allows such an untracked
-	but explicitly ignored file to be overwritten.
+	but explicitly ignored file to be overwritten. Incompatible
+	with `--exclude-standard`.
+
+--exclude-standard::
+	When updating the worktree use the standard Git exclusions:
+	.git/info/exclude, .gitignore in each directory, and the user's global
+	exclusion file when deciding if it is safe to overwrite a file.
+	Incompatible with `--exclude-per-directory`.
 
 --index-output=<file>::
 	Instead of writing the results out to `$GIT_INDEX_FILE`,
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 23735adde9..5df493c4a7 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -50,6 +50,40 @@ static int index_output_cb(const struct option *opt, const char *arg,
 	return 0;
 }
 
+enum exclude_type {
+	EXCLUDE_NONE,
+	EXCLUDE_PER_DIRECTORY,
+	EXCLUDE_STANDARD
+} exclude_opt = EXCLUDE_NONE;
+
+static int exclude_error(enum exclude_type exclude)
+{
+	if (exclude == exclude_opt)
+		return error("more than one --exclude-per-directory given");
+	else
+		return error("cannot combine --exclude-per-directory and "
+			     "--exclude-standard");
+}
+
+static int option_parse_exclude_standard(const struct option *opt,
+					 const char *arg, int unset)
+{
+	struct unpack_trees_options *opts;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (exclude_opt == EXCLUDE_PER_DIRECTORY)
+		return exclude_error(EXCLUDE_STANDARD);
+
+	opts = (struct unpack_trees_options *)opt->value;
+	opts->dir = xcalloc(1, sizeof(*opts->dir));
+	setup_standard_excludes(opts->dir);
+	exclude_opt = EXCLUDE_STANDARD;
+
+	return 0;
+}
+
 static int exclude_per_directory_cb(const struct option *opt, const char *arg,
 				    int unset)
 {
@@ -61,12 +95,13 @@ static int exclude_per_directory_cb(const struct option *opt, const char *arg,
 	opts = (struct unpack_trees_options *)opt->value;
 
 	if (opts->dir)
-		die("more than one --exclude-per-directory given.");
+		return exclude_error(EXCLUDE_PER_DIRECTORY);
 
 	dir = xcalloc(1, sizeof(*opts->dir));
 	dir->flags |= DIR_SHOW_IGNORED;
 	dir->exclude_per_dir = arg;
 	opts->dir = dir;
+	exclude_opt = EXCLUDE_PER_DIRECTORY;
 	/* We do not need to nor want to do read-directory
 	 * here; we are merely interested in reusing the
 	 * per directory ignore stack mechanism.
@@ -147,6 +182,10 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 		  N_("gitignore"),
 		  N_("allow explicitly ignored files to be overwritten"),
 		  PARSE_OPT_NONEG, exclude_per_directory_cb },
+		{ OPTION_CALLBACK, 0, "exclude-standard", &opts, NULL,
+			N_("add the standard git exclusions"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			option_parse_exclude_standard },
 		OPT_BOOL('i', NULL, &opts.index_only,
 			 N_("don't check the working tree after merging")),
 		OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
@@ -219,10 +258,16 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 		opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
 	}
 	if ((opts.dir && !opts.update))
-		die("--exclude-per-directory is meaningless unless -u");
-	if (opts.dir && opts.reset == UNPACK_RESET_OVERWRITE_UNTRACKED)
-		warning("--exclude-per-directory without --preserve-untracked "
-			"has no effect");
+		die("%s requires -u", exclude_opt == EXCLUDE_STANDARD ?
+			"--exclude-standard" :" --exclude-per-directory");
+	if (opts.dir && opts.reset == UNPACK_RESET_OVERWRITE_UNTRACKED) {
+		if (exclude_opt == EXCLUDE_STANDARD)
+			die("--reset with --exclude-standard requires "
+			    "--protect-untracked");
+		else
+			warning("--exclude-per-directory without "
+				"--preserve-untracked has no effect");
+	}
 	if (opts.merge && !opts.index_only)
 		setup_work_tree();
 
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index 6c9dd6805b..2e2a6a0c69 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -30,6 +30,20 @@ test_expect_success '--protect-untracked option sanity checks' '
 	read_tree_u_must_fail -m -u --no-protect-untracked
 '
 
+test_expect_success 'exclude option sanity checks' '
+	read_tree_u_must_fail --reset -u --exclude-standard HEAD &&
+	read_tree_u_must_fail --reset --protect-untracked --exclude-standard &&
+	read_tree_u_must_fail --reset -u --protect-untracked \
+			      --exclude-standard \
+			      --exclude-per-directory=.gitignore HEAD &&
+	read_tree_u_must_fail --reset -u --protect-untracked \
+			      --exclude-per-directory=gitignore \
+			      --exclude-per-directory=.gitignore HEAD &&
+	read_tree_u_must_fail --reset --exclude-per-directory=.gitignore HEAD &&
+	read_tree_u_must_succeed --reset -u --exclude-per-directory=.gitignore \
+				 HEAD
+'
+
 test_expect_success 'reset should reset worktree' '
 	echo changed >df &&
 	read_tree_u_must_succeed -u --reset HEAD^ &&
@@ -53,12 +67,24 @@ test_expect_success 'reset --protect-untracked protects untracked directory' '
 	test_cmp expected-err actual-err
 '
 
-test_expect_success 'reset --protect-untracked resets' '
-	rm -rf new &&
+test_expect_success 'reset --protect-untracked --exclude-standard overwrites ignored path' '
+	test_when_finished "rm .git/info/exclude" &&
+	echo missing >.git/info/exclude &&
+	read_tree_u_must_fail -u --reset --protect-untracked \
+			      --exclude-standard HEAD &&
+	echo new >.git/info/exclude &&
 	echo changed >df/file &&
-	read_tree_u_must_succeed -u --reset --protect-untracked HEAD &&
-	git ls-files >actual-two &&
-	test_cmp expect-two actual-two
+	read_tree_u_must_succeed -u --reset --protect-untracked \
+				 --exclude-standard HEAD &&
+	git ls-files >actual &&
+	test_cmp expect-two actual
+'
+
+test_expect_success 'reset --protect-untracked resets' '
+	echo changed >df &&
+	read_tree_u_must_succeed -u --reset --protect-untracked HEAD^ &&
+	git ls-files >actual &&
+	test_cmp expect actual
 '
 
 test_expect_success 'reset should remove remnants from a failed merge' '
diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh
index 91a6fafcb4..728280d40d 100755
--- a/t/t1013-read-tree-submodule.sh
+++ b/t/t1013-read-tree-submodule.sh
@@ -6,9 +6,8 @@ test_description='read-tree can handle submodules'
 . "$TEST_DIRECTORY"/lib-submodule-update.sh
 
 KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
-KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
 
-test_submodule_switch_recursing_with_args "read-tree -u -m"
+test_submodule_switch_recursing_with_args "read-tree -u -m --exclude-standard"
 
 test_submodule_forced_switch_recursing_with_args "read-tree -u --reset"
 
-- 
2.21.0


  parent reply	other threads:[~2019-05-01 10:14 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-01 10:14 [PATCH 0/2] read-tree: improve untracked file support Phillip Wood
2019-05-01 10:14 ` [PATCH 1/2] read-tree --reset: add --protect-untracked Phillip Wood
2019-05-01 10:18   ` Duy Nguyen
2019-05-01 10:32     ` Duy Nguyen
2019-05-02 10:38   ` Duy Nguyen
2019-05-03 15:20     ` Phillip Wood
2019-05-01 10:14 ` Phillip Wood [this message]
2019-05-01 10:31 ` [PATCH 0/2] read-tree: improve untracked file support Duy Nguyen
2019-05-01 14:58   ` Phillip Wood
2019-05-02 10:53     ` Duy Nguyen
2019-05-07 10:01       ` Phillip Wood
2019-05-07 11:02         ` Duy Nguyen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190501101403.20294-3-phillip.wood123@gmail.com \
    --to=phillip.wood123@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=pclouds@gmail.com \
    --cc=phillip.wood@dunelm.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).