commit: support the --pathspec-from-file option
Decisions taken for simplicity: 1) For now, `--pathspec-from-file` is declared incompatible with `--interactive/--patch`, even when <file> is not `stdin`. Such use case it not really expected. Also, it would require changes to `interactive_add()`. 2) It is not allowed to pass pathspec in both args and file. Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									66a25a7242
								
							
						
					
					
						commit
						e440fc5888
					
				|  | @ -13,7 +13,8 @@ SYNOPSIS | ||||||
| 	   [-F <file> | -m <msg>] [--reset-author] [--allow-empty] | 	   [-F <file> | -m <msg>] [--reset-author] [--allow-empty] | ||||||
| 	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>] | 	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>] | ||||||
| 	   [--date=<date>] [--cleanup=<mode>] [--[no-]status] | 	   [--date=<date>] [--cleanup=<mode>] [--[no-]status] | ||||||
| 	   [-i | -o] [-S[<keyid>]] [--] [<pathspec>...] | 	   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]] | ||||||
|  | 	   [-S[<keyid>]] [--] [<pathspec>...] | ||||||
|  |  | ||||||
| DESCRIPTION | DESCRIPTION | ||||||
| ----------- | ----------- | ||||||
|  | @ -278,6 +279,19 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].) | ||||||
| 	already been staged. If used together with `--allow-empty` | 	already been staged. If used together with `--allow-empty` | ||||||
| 	paths are also not required, and an empty commit will be created. | 	paths are also not required, and an empty commit will be created. | ||||||
|  |  | ||||||
|  | --pathspec-from-file=<file>:: | ||||||
|  | 	Pathspec is passed in `<file>` instead of commandline args. If | ||||||
|  | 	`<file>` is exactly `-` then standard input is used. Pathspec | ||||||
|  | 	elements are separated by LF or CR/LF. Pathspec elements can be | ||||||
|  | 	quoted as explained for the configuration variable `core.quotePath` | ||||||
|  | 	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and | ||||||
|  | 	global `--literal-pathspecs`. | ||||||
|  |  | ||||||
|  | --pathspec-file-nul:: | ||||||
|  | 	Only meaningful with `--pathspec-from-file`. Pathspec elements are | ||||||
|  | 	separated with NUL character and all other characters are taken | ||||||
|  | 	literally (including newlines and quotes). | ||||||
|  |  | ||||||
| -u[<mode>]:: | -u[<mode>]:: | ||||||
| --untracked-files[=<mode>]:: | --untracked-files[=<mode>]:: | ||||||
| 	Show untracked files. | 	Show untracked files. | ||||||
|  |  | ||||||
|  | @ -107,9 +107,9 @@ static int all, also, interactive, patch_interactive, only, amend, signoff; | ||||||
| static int edit_flag = -1; /* unspecified */ | static int edit_flag = -1; /* unspecified */ | ||||||
| static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; | static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; | ||||||
| static int config_commit_verbose = -1; /* unspecified */ | static int config_commit_verbose = -1; /* unspecified */ | ||||||
| static int no_post_rewrite, allow_empty_message; | static int no_post_rewrite, allow_empty_message, pathspec_file_nul; | ||||||
| static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg; | static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg; | ||||||
| static char *sign_commit; | static char *sign_commit, *pathspec_from_file; | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * The default commit message cleanup mode will remove the lines |  * The default commit message cleanup mode will remove the lines | ||||||
|  | @ -343,6 +343,23 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix | ||||||
| 		       PATHSPEC_PREFER_FULL, | 		       PATHSPEC_PREFER_FULL, | ||||||
| 		       prefix, argv); | 		       prefix, argv); | ||||||
|  |  | ||||||
|  | 	if (pathspec_from_file) { | ||||||
|  | 		if (interactive) | ||||||
|  | 			die(_("--pathspec-from-file is incompatible with --interactive/--patch")); | ||||||
|  |  | ||||||
|  | 		if (pathspec.nr) | ||||||
|  | 			die(_("--pathspec-from-file is incompatible with pathspec arguments")); | ||||||
|  |  | ||||||
|  | 		parse_pathspec_file(&pathspec, 0, | ||||||
|  | 				    PATHSPEC_PREFER_FULL, | ||||||
|  | 				    prefix, pathspec_from_file, pathspec_file_nul); | ||||||
|  | 	} else if (pathspec_file_nul) { | ||||||
|  | 		die(_("--pathspec-file-nul requires --pathspec-from-file")); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!pathspec.nr && (also || (only && !amend && !allow_empty))) | ||||||
|  | 		die(_("No paths with --include/--only does not make sense.")); | ||||||
|  |  | ||||||
| 	if (read_cache_preload(&pathspec) < 0) | 	if (read_cache_preload(&pathspec) < 0) | ||||||
| 		die(_("index file corrupt")); | 		die(_("index file corrupt")); | ||||||
|  |  | ||||||
|  | @ -1198,8 +1215,6 @@ static int parse_and_validate_options(int argc, const char *argv[], | ||||||
|  |  | ||||||
| 	if (also + only + all + interactive > 1) | 	if (also + only + all + interactive > 1) | ||||||
| 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); | 		die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); | ||||||
| 	if (argc == 0 && (also || (only && !amend && !allow_empty))) |  | ||||||
| 		die(_("No paths with --include/--only does not make sense.")); |  | ||||||
| 	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor); | 	cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor); | ||||||
|  |  | ||||||
| 	handle_untracked_files_arg(s); | 	handle_untracked_files_arg(s); | ||||||
|  | @ -1535,6 +1550,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) | ||||||
| 		OPT_BOOL(0, "amend", &amend, N_("amend previous commit")), | 		OPT_BOOL(0, "amend", &amend, N_("amend previous commit")), | ||||||
| 		OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), | 		OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), | ||||||
| 		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, | 		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, | ||||||
|  | 		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), | ||||||
|  | 		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), | ||||||
| 		/* end commit contents options */ | 		/* end commit contents options */ | ||||||
|  |  | ||||||
| 		OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty, | 		OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty, | ||||||
|  |  | ||||||
|  | @ -0,0 +1,130 @@ | ||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | test_description='commit --pathspec-from-file' | ||||||
|  |  | ||||||
|  | . ./test-lib.sh | ||||||
|  |  | ||||||
|  | test_tick | ||||||
|  |  | ||||||
|  | test_expect_success setup ' | ||||||
|  | 	test_commit file0 && | ||||||
|  | 	git tag checkpoint && | ||||||
|  |  | ||||||
|  | 	echo A >fileA.t && | ||||||
|  | 	echo B >fileB.t && | ||||||
|  | 	echo C >fileC.t && | ||||||
|  | 	echo D >fileD.t && | ||||||
|  | 	git add fileA.t fileB.t fileC.t fileD.t | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | restore_checkpoint () { | ||||||
|  | 	git reset --soft checkpoint | ||||||
|  | } | ||||||
|  |  | ||||||
|  | verify_expect () { | ||||||
|  | 	git diff-tree --no-commit-id --name-status -r HEAD >actual && | ||||||
|  | 	test_cmp expect actual | ||||||
|  | } | ||||||
|  |  | ||||||
|  | test_expect_success '--pathspec-from-file from stdin' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	echo fileA.t | git commit --pathspec-from-file=- -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success '--pathspec-from-file from file' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	echo fileA.t >list && | ||||||
|  | 	git commit --pathspec-from-file=list -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'NUL delimiters' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "fileA.t\0fileB.t\0" | git commit --pathspec-from-file=- --pathspec-file-nul -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	A	fileB.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'LF delimiters' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "fileA.t\nfileB.t\n" | git commit --pathspec-from-file=- -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	A	fileB.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'no trailing delimiter' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "fileA.t\nfileB.t" | git commit --pathspec-from-file=- -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	A	fileB.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'CRLF delimiters' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "fileA.t\r\nfileB.t\r\n" | git commit --pathspec-from-file=- -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	A	fileB.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'quotes' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "\"file\\101.t\"" | git commit --pathspec-from-file=- -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileA.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'quotes not compatible with --pathspec-file-nul' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "\"file\\101.t\"" >list && | ||||||
|  | 	test_must_fail git commit --pathspec-from-file=list --pathspec-file-nul -m "Commit" | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'only touches what was listed' ' | ||||||
|  | 	restore_checkpoint && | ||||||
|  |  | ||||||
|  | 	printf "fileB.t\nfileC.t\n" | git commit --pathspec-from-file=- -m "Commit" && | ||||||
|  |  | ||||||
|  | 	cat >expect <<-\EOF && | ||||||
|  | 	A	fileB.t | ||||||
|  | 	A	fileC.t | ||||||
|  | 	EOF | ||||||
|  | 	verify_expect | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_done | ||||||
		Loading…
	
		Reference in New Issue
	
	 Alexandr Miloslavskiy
						Alexandr Miloslavskiy