The only notable user-visible/incompatible change is that the --build-fake-ancestor option now conforms to gitcli(7). Signed-off-by: Miklos Vajna <vmiklos@xxxxxxxxxxxxxx> --- I know that we do care about incompatible changes a lot, though I think this is the right direction and probably --build-fake-ancestor is not a heavily used switch, so I hope that part is OK. Documentation/git-apply.txt | 4 +- builtin-apply.c | 360 ++++++++++++++++++++++++++++--------------- 2 files changed, 234 insertions(+), 130 deletions(-) diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index e726510..9400f6a 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] '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] [-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached] [--whitespace=<nowarn|warn|fix|error|error-all>] @@ -64,7 +64,7 @@ OPTIONS cached data, apply the patch, and store the result in the 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' for each blob to help identify the original version that the patch applies to. When this flag is given, and if diff --git a/builtin-apply.c b/builtin-apply.c index 07244b0..c2a587f 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -14,6 +14,7 @@ #include "builtin.h" #include "string-list.h" #include "dir.h" +#include "parse-options.h" /* * --check turns on checking that the working tree matches the @@ -46,8 +47,10 @@ static int no_add; static const char *fake_ancestor; static int line_termination = '\n'; static unsigned long p_context = ULONG_MAX; -static const char 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>..."; +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>...", + NULL +}; static enum ws_error_action { nowarn_ws_error, @@ -61,6 +64,8 @@ static int applied_after_fixing_ws; static const char *patch_input_file; static const char *root; static int root_len; +static int read_stdin = 1; +static int options; static void parse_whitespace_option(const char *option) { @@ -3135,150 +3140,249 @@ static int git_apply_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } +static int option_parse_stdin(const struct option *opt, + const char *arg, int unset) +{ + int *errs = opt->value; + + *errs |= apply_patch(0, "<stdin>", options); + read_stdin = 0; + return 0; +} + +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_stat(const struct option *opt, + const char *arg, int unset) +{ + apply = 0; + diffstat = 1; + return 0; +} + +static int option_parse_numstat(const struct option *opt, + const char *arg, int unset) +{ + apply = 0; + numstat = 1; + return 0; +} + +static int option_parse_summary(const struct option *opt, + const char *arg, int unset) +{ + apply = 0; + summary = 1; + return 0; +} + +static int option_parse_check(const struct option *opt, + const char *arg, int unset) +{ + apply = 0; + check = 1; + return 0; +} + +static int option_parse_index(const struct option *opt, + const char *arg, int unset) +{ + int *is_not_gitdir = opt->value; + + if (*is_not_gitdir) + die("--index outside a repository"); + check_index = 1; + return 0; +} + +static int option_parse_cached(const struct option *opt, + const char *arg, int unset) +{ + int *is_not_gitdir = opt->value; + + if (*is_not_gitdir) + die("--cached outside a repository"); + check_index = 1; + cached = 1; + return 0; +} + +static int option_parse_ancestor(const struct option *opt, + const char *arg, int unset) +{ + apply = 0; + fake_ancestor = arg; + 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_reject(const struct option *opt, + const char *arg, int unset) +{ + apply = apply_with_reject = apply_verbosely = 1; + return 0; +} + +static int option_parse_inaccurate(const struct option *opt, + const char *arg, int unset) +{ + options |= INACCURATE_EOF; + return 0; +} + +static int option_parse_recount(const struct option *opt, + const char *arg, int unset) +{ + options |= RECOUNT; + 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 i; - int read_stdin = 1; - int options = 0; int errs = 0; int is_not_gitdir; + int binary; const char *whitespace_option = NULL; + struct option builtin_apply_options[] = { + { OPTION_CALLBACK, '-', NULL, &errs, NULL, + "read the patch from the standard input", + PARSE_OPT_NOARG, option_parse_stdin }, + { 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"), + { OPTION_CALLBACK, 0, "stat", NULL, NULL, + "instead of applying the patch, output diffstat for the input", + PARSE_OPT_NOARG, option_parse_stat }, + OPT_BOOLEAN(0, "allow-binary-replacement", &binary, + "now no-op"), + OPT_BOOLEAN(0, "binary", &binary, + "now no-op"), + { OPTION_CALLBACK, 0, "numstat", NULL, NULL, + "shows number of added and deleted lines in decimal notation", + PARSE_OPT_NOARG, option_parse_numstat }, + { OPTION_CALLBACK, 0, "summary", NULL, NULL, + "instead of applying the patch, output a summary for the input", + PARSE_OPT_NOARG, option_parse_summary }, + { OPTION_CALLBACK, 0, "check", NULL, NULL, + "instead of applying the patch, see if the patch is applicable", + PARSE_OPT_NOARG, option_parse_check }, + { OPTION_CALLBACK, 0, "index", &is_not_gitdir, NULL, + "make sure the patch is applicable to the current index", + PARSE_OPT_NOARG, option_parse_index }, + { OPTION_CALLBACK, 0, "cached", &is_not_gitdir, NULL, + "apply a patch without touching the working tree", + PARSE_OPT_NOARG, option_parse_cached }, + OPT_BOOLEAN(0, "apply", &apply, + "also apply the patch (use with --stat/--summary/--check)"), + { OPTION_CALLBACK, 0, "build-fake-ancestor", NULL, "file", + "build a temporary index based on embedded index information", + 0, option_parse_ancestor }, + { 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"), + { OPTION_CALLBACK, 0, "reject", NULL, NULL, + "leave the rejected hunks in corresponding *.rej files", + PARSE_OPT_NOARG, option_parse_reject }, + OPT__VERBOSE(&apply_verbosely), + { OPTION_CALLBACK, 0, "inaccurate-eof", NULL, NULL, + "tolerate incorrectly detected missing new-line at the end of file", + PARSE_OPT_NOARG, option_parse_inaccurate }, + { OPTION_CALLBACK, 0, "recount", NULL, NULL, + "do not trust the line counts in the hunk headers", + PARSE_OPT_NOARG, option_parse_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_length = prefix ? strlen(prefix) : 0; git_config(git_apply_config, NULL); if (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); + + for (i = 0; i < argc; i++) { const char *arg = argv[i]; - char *end; int fd; - if (!strcmp(arg, "-")) { - errs |= apply_patch(0, "<stdin>", options); - read_stdin = 0; - continue; - } - 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); -- 1.6.1.rc1.35.gae26e.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html