Merge branch 'mv/apply-parse-opt'

* mv/apply-parse-opt:
  Resurrect "git apply --flags -" to read from the standard input
  parse-opt: migrate builtin-apply.
This commit is contained in:
Junio C Hamano 2009-01-17 23:06:53 -08:00
Родитель 90abc19b5a 64912a67a4
Коммит 8f31355692
3 изменённых файлов: 168 добавлений и 128 удалений

Просмотреть файл

@ -10,7 +10,7 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git apply' [--stat] [--numstat] [--summary] [--check] [--index] 'git apply' [--stat] [--numstat] [--summary] [--check] [--index]
[--apply] [--no-add] [--build-fake-ancestor <file>] [-R | --reverse] [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z] [--allow-binary-replacement | --binary] [--reject] [-z]
[-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached] [-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached]
[--whitespace=<nowarn|warn|fix|error|error-all>] [--whitespace=<nowarn|warn|fix|error|error-all>]
@ -64,7 +64,7 @@ OPTIONS
cached data, apply the patch, and store the result in the index, cached data, apply the patch, and store the result in the index,
without using the working tree. This implies '--index'. without using the working tree. This implies '--index'.
--build-fake-ancestor <file>:: --build-fake-ancestor=<file>::
Newer 'git-diff' output has embedded 'index information' Newer 'git-diff' output has embedded 'index information'
for each blob to help identify the original version that for each blob to help identify the original version that
the patch applies to. When this flag is given, and if the patch applies to. When this flag is given, and if

Просмотреть файл

@ -14,6 +14,7 @@
#include "builtin.h" #include "builtin.h"
#include "string-list.h" #include "string-list.h"
#include "dir.h" #include "dir.h"
#include "parse-options.h"
/* /*
* --check turns on checking that the working tree matches the * --check turns on checking that the working tree matches the
@ -45,9 +46,11 @@ static int apply_verbosely;
static int no_add; static int no_add;
static const char *fake_ancestor; static const char *fake_ancestor;
static int line_termination = '\n'; static int line_termination = '\n';
static unsigned long p_context = ULONG_MAX; static unsigned int p_context = UINT_MAX;
static const char apply_usage[] = static const char * const apply_usage[] = {
"git apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>..."; "git apply [options] [<patch>...]",
NULL
};
static enum ws_error_action { static enum ws_error_action {
nowarn_ws_error, nowarn_ws_error,
@ -61,6 +64,8 @@ static int applied_after_fixing_ws;
static const char *patch_input_file; static const char *patch_input_file;
static const char *root; static const char *root;
static int root_len; static int root_len;
static int read_stdin = 1;
static int options;
static void parse_whitespace_option(const char *option) static void parse_whitespace_option(const char *option)
{ {
@ -3137,151 +3142,160 @@ static int git_apply_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb); return git_default_config(var, value, cb);
} }
static int option_parse_exclude(const struct option *opt,
const char *arg, int unset)
{
add_name_limit(arg, 1);
return 0;
}
static int option_parse_include(const struct option *opt,
const char *arg, int unset)
{
add_name_limit(arg, 0);
has_include = 1;
return 0;
}
static int option_parse_p(const struct option *opt,
const char *arg, int unset)
{
p_value = atoi(arg);
p_value_known = 1;
return 0;
}
static int option_parse_z(const struct option *opt,
const char *arg, int unset)
{
if (unset)
line_termination = '\n';
else
line_termination = 0;
return 0;
}
static int option_parse_whitespace(const struct option *opt,
const char *arg, int unset)
{
const char **whitespace_option = opt->value;
*whitespace_option = arg;
parse_whitespace_option(arg);
return 0;
}
static int option_parse_directory(const struct option *opt,
const char *arg, int unset)
{
root_len = strlen(arg);
if (root_len && arg[root_len - 1] != '/') {
char *new_root;
root = new_root = xmalloc(root_len + 2);
strcpy(new_root, arg);
strcpy(new_root + root_len++, "/");
} else
root = arg;
return 0;
}
int cmd_apply(int argc, const char **argv, const char *unused_prefix) int cmd_apply(int argc, const char **argv, const char *unused_prefix)
{ {
int i; int i;
int read_stdin = 1;
int options = 0;
int errs = 0; int errs = 0;
int is_not_gitdir; int is_not_gitdir;
int binary;
int force_apply = 0;
const char *whitespace_option = NULL; const char *whitespace_option = NULL;
struct option builtin_apply_options[] = {
{ OPTION_CALLBACK, 0, "exclude", NULL, "path",
"don´t apply changes matching the given path",
0, option_parse_exclude },
{ OPTION_CALLBACK, 0, "include", NULL, "path",
"apply changes matching the given path",
0, option_parse_include },
{ OPTION_CALLBACK, 'p', NULL, NULL, "num",
"remove <num> leading slashes from traditional diff paths",
0, option_parse_p },
OPT_BOOLEAN(0, "no-add", &no_add,
"ignore additions made by the patch"),
OPT_BOOLEAN(0, "stat", &diffstat,
"instead of applying the patch, output diffstat for the input"),
OPT_BOOLEAN(0, "allow-binary-replacement", &binary,
"now no-op"),
OPT_BOOLEAN(0, "binary", &binary,
"now no-op"),
OPT_BOOLEAN(0, "numstat", &numstat,
"shows number of added and deleted lines in decimal notation"),
OPT_BOOLEAN(0, "summary", &summary,
"instead of applying the patch, output a summary for the input"),
OPT_BOOLEAN(0, "check", &check,
"instead of applying the patch, see if the patch is applicable"),
OPT_BOOLEAN(0, "index", &check_index,
"make sure the patch is applicable to the current index"),
OPT_BOOLEAN(0, "cached", &cached,
"apply a patch without touching the working tree"),
OPT_BOOLEAN(0, "apply", &force_apply,
"also apply the patch (use with --stat/--summary/--check)"),
OPT_STRING(0, "build-fake-ancestor", &fake_ancestor, "file",
"build a temporary index based on embedded index information"),
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
"paths are separated with NUL character",
PARSE_OPT_NOARG, option_parse_z },
OPT_INTEGER('C', NULL, &p_context,
"ensure at least <n> lines of context match"),
{ OPTION_CALLBACK, 0, "whitespace", &whitespace_option, "action",
"detect new or modified lines that have whitespace errors",
0, option_parse_whitespace },
OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
"apply the patch in reverse"),
OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
"don't expect at least one line of context"),
OPT_BOOLEAN(0, "reject", &apply_with_reject,
"leave the rejected hunks in corresponding *.rej files"),
OPT__VERBOSE(&apply_verbosely),
OPT_BIT(0, "inaccurate-eof", &options,
"tolerate incorrectly detected missing new-line at the end of file",
INACCURATE_EOF),
OPT_BIT(0, "recount", &options,
"do not trust the line counts in the hunk headers",
RECOUNT),
{ OPTION_CALLBACK, 0, "directory", NULL, "root",
"prepend <root> to all filenames",
0, option_parse_directory },
OPT_END()
};
prefix = setup_git_directory_gently(&is_not_gitdir); prefix = setup_git_directory_gently(&is_not_gitdir);
prefix_length = prefix ? strlen(prefix) : 0; prefix_length = prefix ? strlen(prefix) : 0;
git_config(git_apply_config, NULL); git_config(git_apply_config, NULL);
if (apply_default_whitespace) if (apply_default_whitespace)
parse_whitespace_option(apply_default_whitespace); parse_whitespace_option(apply_default_whitespace);
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, builtin_apply_options,
apply_usage, 0);
if (apply_with_reject)
apply = apply_verbosely = 1;
if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
apply = 0;
if (check_index && is_not_gitdir)
die("--index outside a repository");
if (cached) {
if (is_not_gitdir)
die("--cached outside a repository");
check_index = 1;
}
for (i = 0; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];
char *end;
int fd; int fd;
if (!strcmp(arg, "-")) { if (!strcmp(arg, "-")) {
errs |= apply_patch(0, "<stdin>", options); errs |= apply_patch(0, "<stdin>", options);
read_stdin = 0; read_stdin = 0;
continue; continue;
} } else if (0 < prefix_length)
if (!prefixcmp(arg, "--exclude=")) {
add_name_limit(arg + 10, 1);
continue;
}
if (!prefixcmp(arg, "--include=")) {
add_name_limit(arg + 10, 0);
has_include = 1;
continue;
}
if (!prefixcmp(arg, "-p")) {
p_value = atoi(arg + 2);
p_value_known = 1;
continue;
}
if (!strcmp(arg, "--no-add")) {
no_add = 1;
continue;
}
if (!strcmp(arg, "--stat")) {
apply = 0;
diffstat = 1;
continue;
}
if (!strcmp(arg, "--allow-binary-replacement") ||
!strcmp(arg, "--binary")) {
continue; /* now no-op */
}
if (!strcmp(arg, "--numstat")) {
apply = 0;
numstat = 1;
continue;
}
if (!strcmp(arg, "--summary")) {
apply = 0;
summary = 1;
continue;
}
if (!strcmp(arg, "--check")) {
apply = 0;
check = 1;
continue;
}
if (!strcmp(arg, "--index")) {
if (is_not_gitdir)
die("--index outside a repository");
check_index = 1;
continue;
}
if (!strcmp(arg, "--cached")) {
if (is_not_gitdir)
die("--cached outside a repository");
check_index = 1;
cached = 1;
continue;
}
if (!strcmp(arg, "--apply")) {
apply = 1;
continue;
}
if (!strcmp(arg, "--build-fake-ancestor")) {
apply = 0;
if (++i >= argc)
die ("need a filename");
fake_ancestor = argv[i];
continue;
}
if (!strcmp(arg, "-z")) {
line_termination = 0;
continue;
}
if (!prefixcmp(arg, "-C")) {
p_context = strtoul(arg + 2, &end, 0);
if (*end != '\0')
die("unrecognized context count '%s'", arg + 2);
continue;
}
if (!prefixcmp(arg, "--whitespace=")) {
whitespace_option = arg + 13;
parse_whitespace_option(arg + 13);
continue;
}
if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
apply_in_reverse = 1;
continue;
}
if (!strcmp(arg, "--unidiff-zero")) {
unidiff_zero = 1;
continue;
}
if (!strcmp(arg, "--reject")) {
apply = apply_with_reject = apply_verbosely = 1;
continue;
}
if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
apply_verbosely = 1;
continue;
}
if (!strcmp(arg, "--inaccurate-eof")) {
options |= INACCURATE_EOF;
continue;
}
if (!strcmp(arg, "--recount")) {
options |= RECOUNT;
continue;
}
if (!prefixcmp(arg, "--directory=")) {
arg += strlen("--directory=");
root_len = strlen(arg);
if (root_len && arg[root_len - 1] != '/') {
char *new_root;
root = new_root = xmalloc(root_len + 2);
strcpy(new_root, arg);
strcpy(new_root + root_len++, "/");
} else
root = arg;
continue;
}
if (0 < prefix_length)
arg = prefix_filename(prefix, prefix_length, arg); arg = prefix_filename(prefix, prefix_length, arg);
fd = open(arg, O_RDONLY); fd = open(arg, O_RDONLY);

26
t/t4106-apply-stdin.sh Executable file
Просмотреть файл

@ -0,0 +1,26 @@
#!/bin/sh
test_description='git apply --numstat - <patch'
. ./test-lib.sh
test_expect_success setup '
echo hello >text &&
git add text &&
echo goodbye >text &&
git diff >patch
'
test_expect_success 'git apply --numstat - < patch' '
echo "1 1 text" >expect &&
git apply --numstat - <patch >actual &&
test_cmp expect actual
'
test_expect_success 'git apply --numstat - < patch patch' '
for i in 1 2; do echo "1 1 text"; done >expect &&
git apply --numstat - < patch patch >actual &&
test_cmp expect actual
'
test_done