зеркало из https://github.com/microsoft/git.git
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:
Коммит
8f31355692
|
@ -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
|
||||||
|
|
266
builtin-apply.c
266
builtin-apply.c
|
@ -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);
|
||||||
|
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче