summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c33
-rw-r--r--builtin/am.c14
-rw-r--r--builtin/apply.c1436
-rw-r--r--builtin/blame.c26
-rw-r--r--builtin/cat-file.c21
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/clone.c9
-rw-r--r--builtin/commit.c19
-rw-r--r--builtin/fetch.c6
-rw-r--r--builtin/interpret-trailers.c2
-rw-r--r--builtin/log.c14
-rw-r--r--builtin/mailsplit.c18
-rw-r--r--builtin/pack-objects.c31
-rw-r--r--builtin/patch-id.c23
-rw-r--r--builtin/pull.c3
-rw-r--r--builtin/receive-pack.c15
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/repack.c10
-rw-r--r--builtin/reset.c4
-rw-r--r--builtin/rev-list.c6
-rw-r--r--builtin/shortlog.c6
-rw-r--r--builtin/submodule--helper.c89
-rw-r--r--builtin/update-index.c2
-rw-r--r--builtin/worktree.c13
24 files changed, 1104 insertions, 700 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 145f06e..b1dddb4 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -26,7 +26,7 @@ static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
struct update_callback_data {
- int flags;
+ int flags, force_mode;
int add_errors;
};
@@ -65,7 +65,8 @@ static void update_callback(struct diff_queue_struct *q,
die(_("unexpected diff status %c"), p->status);
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
- if (add_file_to_index(&the_index, path, data->flags)) {
+ if (add_file_to_index(&the_index, path,
+ data->flags, data->force_mode)) {
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
die(_("updating files failed"));
data->add_errors++;
@@ -83,14 +84,15 @@ static void update_callback(struct diff_queue_struct *q,
}
}
-int add_files_to_cache(const char *prefix,
- const struct pathspec *pathspec, int flags)
+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec,
+ int flags, int force_mode)
{
struct update_callback_data data;
struct rev_info rev;
memset(&data, 0, sizeof(data));
data.flags = flags;
+ data.force_mode = force_mode;
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
@@ -238,6 +240,8 @@ static int ignore_add_errors, intent_to_add, ignore_missing;
static int addremove = ADDREMOVE_DEFAULT;
static int addremove_explicit = -1; /* unspecified */
+static char *chmod_arg;
+
static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
{
/* if we are told to ignore, we are not adding removals */
@@ -263,6 +267,7 @@ static struct option builtin_add_options[] = {
OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
+ OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")),
OPT_END(),
};
@@ -276,7 +281,7 @@ static int add_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
-static int add_files(struct dir_struct *dir, int flags)
+static int add_files(struct dir_struct *dir, int flags, int force_mode)
{
int i, exit_status = 0;
@@ -289,7 +294,8 @@ static int add_files(struct dir_struct *dir, int flags)
}
for (i = 0; i < dir->nr; i++)
- if (add_file_to_cache(dir->entries[i]->name, flags)) {
+ if (add_file_to_index(&the_index, dir->entries[i]->name,
+ flags, force_mode)) {
if (!ignore_add_errors)
die(_("adding files failed"));
exit_status = 1;
@@ -302,7 +308,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int exit_status = 0;
struct pathspec pathspec;
struct dir_struct dir;
- int flags;
+ int flags, force_mode;
int add_new_files;
int require_pathspec;
char *seen = NULL;
@@ -336,6 +342,15 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));
+ if (!chmod_arg)
+ force_mode = 0;
+ else if (!strcmp(chmod_arg, "-x"))
+ force_mode = 0666;
+ else if (!strcmp(chmod_arg, "+x"))
+ force_mode = 0777;
+ else
+ die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
+
add_new_files = !take_worktree_changes && !refresh_only;
require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
@@ -426,10 +441,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
plug_bulk_checkin();
- exit_status |= add_files_to_cache(prefix, &pathspec, flags);
+ exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode);
if (add_new_files)
- exit_status |= add_files(&dir, flags);
+ exit_status |= add_files(&dir, flags, force_mode);
unplug_bulk_checkin();
diff --git a/builtin/am.c b/builtin/am.c
index 3dfe70b..d5da5fe 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -70,7 +70,8 @@ enum patch_format {
PATCH_FORMAT_MBOX,
PATCH_FORMAT_STGIT,
PATCH_FORMAT_STGIT_SERIES,
- PATCH_FORMAT_HG
+ PATCH_FORMAT_HG,
+ PATCH_FORMAT_MBOXRD
};
enum keep_type {
@@ -712,7 +713,8 @@ done:
* Splits out individual email patches from `paths`, where each path is either
* a mbox file or a Maildir. Returns 0 on success, -1 on failure.
*/
-static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
+static int split_mail_mbox(struct am_state *state, const char **paths,
+ int keep_cr, int mboxrd)
{
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf last = STRBUF_INIT;
@@ -724,6 +726,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_
argv_array_push(&cp.args, "-b");
if (keep_cr)
argv_array_push(&cp.args, "--keep-cr");
+ if (mboxrd)
+ argv_array_push(&cp.args, "--mboxrd");
argv_array_push(&cp.args, "--");
argv_array_pushv(&cp.args, paths);
@@ -965,13 +969,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
switch (patch_format) {
case PATCH_FORMAT_MBOX:
- return split_mail_mbox(state, paths, keep_cr);
+ return split_mail_mbox(state, paths, keep_cr, 0);
case PATCH_FORMAT_STGIT:
return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
case PATCH_FORMAT_STGIT_SERIES:
return split_mail_stgit_series(state, paths, keep_cr);
case PATCH_FORMAT_HG:
return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
+ case PATCH_FORMAT_MBOXRD:
+ return split_mail_mbox(state, paths, keep_cr, 1);
default:
die("BUG: invalid patch_format");
}
@@ -2201,6 +2207,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
*opt_value = PATCH_FORMAT_STGIT_SERIES;
else if (!strcmp(arg, "hg"))
*opt_value = PATCH_FORMAT_HG;
+ else if (!strcmp(arg, "mboxrd"))
+ *opt_value = PATCH_FORMAT_MBOXRD;
else
return error(_("Invalid value for --patch-format: %s"), arg);
return 0;
diff --git a/builtin/apply.c b/builtin/apply.c
index 205c9f8f3..1a488f9 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -21,132 +21,161 @@
#include "ll-merge.h"
#include "rerere.h"
-/*
- * --check turns on checking that the working tree matches the
- * files that are being modified, but doesn't apply the patch
- * --stat does just a diffstat, and doesn't actually apply
- * --numstat does numeric diffstat, and doesn't actually apply
- * --index-info shows the old and new index info for paths if available.
- * --index updates the cache as well.
- * --cached updates only the cache without ever touching the working tree.
- */
-static const char *prefix;
-static int prefix_length = -1;
-static int newfd = -1;
-
-static int unidiff_zero;
-static int p_value = 1;
-static int p_value_known;
-static int check_index;
-static int update_index;
-static int cached;
-static int diffstat;
-static int numstat;
-static int summary;
-static int check;
-static int apply = 1;
-static int apply_in_reverse;
-static int apply_with_reject;
-static int apply_verbosely;
-static int allow_overlap;
-static int no_add;
-static int threeway;
-static int unsafe_paths;
-static const char *fake_ancestor;
-static int line_termination = '\n';
-static unsigned int p_context = UINT_MAX;
-static const char * const apply_usage[] = {
- N_("git apply [<options>] [<patch>...]"),
- NULL
-};
-
-static enum ws_error_action {
+enum ws_error_action {
nowarn_ws_error,
warn_on_ws_error,
die_on_ws_error,
correct_ws_error
-} ws_error_action = warn_on_ws_error;
-static int whitespace_error;
-static int squelch_whitespace_errors = 5;
-static int applied_after_fixing_ws;
+};
+
-static enum ws_ignore {
+enum ws_ignore {
ignore_ws_none,
ignore_ws_change
-} ws_ignore_action = ignore_ws_none;
+};
+
+/*
+ * We need to keep track of how symlinks in the preimage are
+ * manipulated by the patches. A patch to add a/b/c where a/b
+ * is a symlink should not be allowed to affect the directory
+ * the symlink points at, but if the same patch removes a/b,
+ * it is perfectly fine, as the patch removes a/b to make room
+ * to create a directory a/b so that a/b/c can be created.
+ *
+ * See also "struct string_list symlink_changes" in "struct
+ * apply_state".
+ */
+#define SYMLINK_GOES_AWAY 01
+#define SYMLINK_IN_RESULT 02
+struct apply_state {
+ const char *prefix;
+ int prefix_length;
+
+ /* These are lock_file related */
+ struct lock_file *lock_file;
+ int newfd;
+
+ /* These control what gets looked at and modified */
+ int apply; /* this is not a dry-run */
+ int cached; /* apply to the index only */
+ int check; /* preimage must match working tree, don't actually apply */
+ int check_index; /* preimage must match the indexed version */
+ int update_index; /* check_index && apply */
+
+ /* These control cosmetic aspect of the output */
+ int diffstat; /* just show a diffstat, and don't actually apply */
+ int numstat; /* just show a numeric diffstat, and don't actually apply */
+ int summary; /* just report creation, deletion, etc, and don't actually apply */
+
+ /* These boolean parameters control how the apply is done */
+ int allow_overlap;
+ int apply_in_reverse;
+ int apply_with_reject;
+ int apply_verbosely;
+ int no_add;
+ int threeway;
+ int unidiff_zero;
+ int unsafe_paths;
+
+ /* Other non boolean parameters */
+ const char *fake_ancestor;
+ const char *patch_input_file;
+ int line_termination;
+ struct strbuf root;
+ int p_value;
+ int p_value_known;
+ unsigned int p_context;
+
+ /* Exclude and include path parameters */
+ struct string_list limit_by_name;
+ int has_include;
+
+ /* Various "current state" */
+ int linenr; /* current line number */
+ struct string_list symlink_changes; /* we have to track symlinks */
-static const char *patch_input_file;
-static struct strbuf root = STRBUF_INIT;
-static int read_stdin = 1;
-static int options;
+ /*
+ * For "diff-stat" like behaviour, we keep track of the biggest change
+ * we've seen, and the longest filename. That allows us to do simple
+ * scaling.
+ */
+ int max_change;
+ int max_len;
-static void parse_whitespace_option(const char *option)
+ /*
+ * Records filenames that have been touched, in order to handle
+ * the case where more than one patches touch the same file.
+ */
+ struct string_list fn_table;
+
+ /* These control whitespace errors */
+ enum ws_error_action ws_error_action;
+ enum ws_ignore ws_ignore_action;
+ const char *whitespace_option;
+ int whitespace_error;
+ int squelch_whitespace_errors;
+ int applied_after_fixing_ws;
+};
+
+static const char * const apply_usage[] = {
+ N_("git apply [<options>] [<patch>...]"),
+ NULL
+};
+
+static void parse_whitespace_option(struct apply_state *state, const char *option)
{
if (!option) {
- ws_error_action = warn_on_ws_error;
+ state->ws_error_action = warn_on_ws_error;
return;
}
if (!strcmp(option, "warn")) {
- ws_error_action = warn_on_ws_error;
+ state->ws_error_action = warn_on_ws_error;
return;
}
if (!strcmp(option, "nowarn")) {
- ws_error_action = nowarn_ws_error;
+ state->ws_error_action = nowarn_ws_error;
return;
}
if (!strcmp(option, "error")) {
- ws_error_action = die_on_ws_error;
+ state->ws_error_action = die_on_ws_error;
return;
}
if (!strcmp(option, "error-all")) {
- ws_error_action = die_on_ws_error;
- squelch_whitespace_errors = 0;
+ state->ws_error_action = die_on_ws_error;
+ state->squelch_whitespace_errors = 0;
return;
}
if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
- ws_error_action = correct_ws_error;
+ state->ws_error_action = correct_ws_error;
return;
}
die(_("unrecognized whitespace option '%s'"), option);
}
-static void parse_ignorewhitespace_option(const char *option)
+static void parse_ignorewhitespace_option(struct apply_state *state,
+ const char *option)
{
if (!option || !strcmp(option, "no") ||
!strcmp(option, "false") || !strcmp(option, "never") ||
!strcmp(option, "none")) {
- ws_ignore_action = ignore_ws_none;
+ state->ws_ignore_action = ignore_ws_none;
return;
}
if (!strcmp(option, "change")) {
- ws_ignore_action = ignore_ws_change;
+ state->ws_ignore_action = ignore_ws_change;
return;
}
die(_("unrecognized whitespace ignore option '%s'"), option);
}
-static void set_default_whitespace_mode(const char *whitespace_option)
+static void set_default_whitespace_mode(struct apply_state *state)
{
- if (!whitespace_option && !apply_default_whitespace)
- ws_error_action = (apply ? warn_on_ws_error : nowarn_ws_error);
+ if (!state->whitespace_option && !apply_default_whitespace)
+ state->ws_error_action = (state->apply ? warn_on_ws_error : nowarn_ws_error);
}
/*
- * For "diff-stat" like behaviour, we keep track of the biggest change
- * we've seen, and the longest filename. That allows us to do simple
- * scaling.
- */
-static int max_change, max_len;
-
-/*
- * Various "current state", notably line numbers and what
- * file (and how) we're patching right now.. The "is_xxxx"
- * things are flags, where -1 means "don't know yet".
- */
-static int linenr = 1;
-
-/*
* This represents one "hunk" from a patch, starting with
* "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
* patch text is pointed at by patch, and its byte length
@@ -265,13 +294,6 @@ struct image {
struct line *line;
};
-/*
- * Records filenames that have been touched, in order to handle
- * the case where more than one patches touch the same file.
- */
-
-static struct string_list fn_table;
-
static uint32_t hash_line(const char *cp, size_t len)
{
size_t i;
@@ -442,7 +464,7 @@ static int is_dev_null(const char *str)
#define TERM_SPACE 1
#define TERM_TAB 2
-static int name_terminate(const char *name, int namelen, int c, int terminate)
+static int name_terminate(int c, int terminate)
{
if (c == ' ' && !(terminate & TERM_SPACE))
return 0;
@@ -469,7 +491,10 @@ static char *squash_slash(char *name)
return name;
}
-static char *find_name_gnu(const char *line, const char *def, int p_value)
+static char *find_name_gnu(struct apply_state *state,
+ const char *line,
+ const char *def,
+ int p_value)
{
struct strbuf name = STRBUF_INIT;
char *cp;
@@ -493,8 +518,8 @@ static char *find_name_gnu(const char *line, const char *def, int p_value)
}
strbuf_remove(&name, 0, cp - name.buf);
- if (root.len)
- strbuf_insert(&name, 0, root.buf, root.len);
+ if (state->root.len)
+ strbuf_insert(&name, 0, state->root.buf, state->root.len);
return squash_slash(strbuf_detach(&name, NULL));
}
@@ -657,8 +682,12 @@ static size_t diff_timestamp_len(const char *line, size_t len)
return line + len - end;
}
-static char *find_name_common(const char *line, const char *def,
- int p_value, const char *end, int terminate)
+static char *find_name_common(struct apply_state *state,
+ const char *line,
+ const char *def,
+ int p_value,
+ const char *end,
+ int terminate)
{
int len;
const char *start = NULL;
@@ -671,7 +700,7 @@ static char *find_name_common(const char *line, const char *def,
if (!end && isspace(c)) {
if (c == '\n')
break;
- if (name_terminate(start, line-start, c, terminate))
+ if (name_terminate(c, terminate))
break;
}
line++;
@@ -696,32 +725,39 @@ static char *find_name_common(const char *line, const char *def,
return squash_slash(xstrdup(def));
}
- if (root.len) {
- char *ret = xstrfmt("%s%.*s", root.buf, len, start);
+ if (state->root.len) {
+ char *ret = xstrfmt("%s%.*s", state->root.buf, len, start);
return squash_slash(ret);
}
return squash_slash(xmemdupz(start, len));
}
-static char *find_name(const char *line, char *def, int p_value, int terminate)
+static char *find_name(struct apply_state *state,
+ const char *line,
+ char *def,
+ int p_value,
+ int terminate)
{
if (*line == '"') {
- char *name = find_name_gnu(line, def, p_value);
+ char *name = find_name_gnu(state, line, def, p_value);
if (name)
return name;
}
- return find_name_common(line, def, p_value, NULL, terminate);
+ return find_name_common(state, line, def, p_value, NULL, terminate);
}
-static char *find_name_traditional(const char *line, char *def, int p_value)
+static char *find_name_traditional(struct apply_state *state,
+ const char *line,
+ char *def,
+ int p_value)
{
size_t len;
size_t date_len;
if (*line == '"') {
- char *name = find_name_gnu(line, def, p_value);
+ char *name = find_name_gnu(state, line, def, p_value);
if (name)
return name;
}
@@ -729,10 +765,10 @@ static char *find_name_traditional(const char *line, char *def, int p_value)
len = strchrnul(line, '\n') - line;
date_len = diff_timestamp_len(line, len);
if (!date_len)
- return find_name_common(line, def, p_value, NULL, TERM_TAB);
+ return find_name_common(state, line, def, p_value, NULL, TERM_TAB);
len -= date_len;
- return find_name_common(line, def, p_value, line + len, 0);
+ return find_name_common(state, line, def, p_value, line + len, 0);
}
static int count_slashes(const char *cp)
@@ -750,30 +786,30 @@ static int count_slashes(const char *cp)
* Given the string after "--- " or "+++ ", guess the appropriate
* p_value for the given patch.
*/
-static int guess_p_value(const char *nameline)
+static int guess_p_value(struct apply_state *state, const char *nameline)
{
char *name, *cp;
int val = -1;
if (is_dev_null(nameline))
return -1;
- name = find_name_traditional(nameline, NULL, 0);
+ name = find_name_traditional(state, nameline, NULL, 0);
if (!name)
return -1;
cp = strchr(name, '/');
if (!cp)
val = 0;
- else if (prefix) {
+ else if (state->prefix) {
/*
* Does it begin with "a/$our-prefix" and such? Then this is
* very likely to apply to our directory.
*/
- if (!strncmp(name, prefix, prefix_length))
- val = count_slashes(prefix);
+ if (!strncmp(name, state->prefix, state->prefix_length))
+ val = count_slashes(state->prefix);
else {
cp++;
- if (!strncmp(cp, prefix, prefix_length))
- val = count_slashes(prefix) + 1;
+ if (!strncmp(cp, state->prefix, state->prefix_length))
+ val = count_slashes(state->prefix) + 1;
}
}
free(name);
@@ -860,36 +896,39 @@ static int has_epoch_timestamp(const char *nameline)
* files, we can happily check the index for a match, but for creating a
* new file we should try to match whatever "patch" does. I have no idea.
*/
-static void parse_traditional_patch(const char *first, const char *second, struct patch *patch)
+static void parse_traditional_patch(struct apply_state *state,
+ const char *first,
+ const char *second,
+ struct patch *patch)
{
char *name;
first += 4; /* skip "--- " */
second += 4; /* skip "+++ " */
- if (!p_value_known) {
+ if (!state->p_value_known) {
int p, q;
- p = guess_p_value(first);
- q = guess_p_value(second);
+ p = guess_p_value(state, first);
+ q = guess_p_value(state, second);
if (p < 0) p = q;
if (0 <= p && p == q) {
- p_value = p;
- p_value_known = 1;
+ state->p_value = p;
+ state->p_value_known = 1;
}
}
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
- name = find_name_traditional(second, NULL, p_value);
+ name = find_name_traditional(state, second, NULL, state->p_value);
patch->new_name = name;
} else if (is_dev_null(second)) {
patch->is_new = 0;
patch->is_delete = 1;
- name = find_name_traditional(first, NULL, p_value);
+ name = find_name_traditional(state, first, NULL, state->p_value);
patch->old_name = name;
} else {
char *first_name;
- first_name = find_name_traditional(first, NULL, p_value);
- name = find_name_traditional(second, first_name, p_value);
+ first_name = find_name_traditional(state, first, NULL, state->p_value);
+ name = find_name_traditional(state, second, first_name, state->p_value);
free(first_name);
if (has_epoch_timestamp(first)) {
patch->is_new = 1;
@@ -905,10 +944,12 @@ static void parse_traditional_patch(const char *first, const char *second, struc
}
}
if (!name)
- die(_("unable to find filename in patch at line %d"), linenr);
+ die(_("unable to find filename in patch at line %d"), state->linenr);
}
-static int gitdiff_hdrend(const char *line, struct patch *patch)
+static int gitdiff_hdrend(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
return -1;
}
@@ -925,107 +966,135 @@ static int gitdiff_hdrend(const char *line, struct patch *patch)
#define DIFF_OLD_NAME 0
#define DIFF_NEW_NAME 1
-static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, int side)
+static void gitdiff_verify_name(struct apply_state *state,
+ const char *line,
+ int isnull,
+ char **name,
+ int side)
{
- if (!orig_name && !isnull)
- return find_name(line, NULL, p_value, TERM_TAB);
+ if (!*name && !isnull) {
+ *name = find_name(state, line, NULL, state->p_value, TERM_TAB);
+ return;
+ }
- if (orig_name) {
- int len = strlen(orig_name);
+ if (*name) {
+ int len = strlen(*name);
char *another;
if (isnull)
die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
- orig_name, linenr);
- another = find_name(line, NULL, p_value, TERM_TAB);
- if (!another || memcmp(another, orig_name, len + 1))
+ *name, state->linenr);
+ another = find_name(state, line, NULL, state->p_value, TERM_TAB);
+ if (!another || memcmp(another, *name, len + 1))
die((side == DIFF_NEW_NAME) ?
_("git apply: bad git-diff - inconsistent new filename on line %d") :
- _("git apply: bad git-diff - inconsistent old filename on line %d"), linenr);
+ _("git apply: bad git-diff - inconsistent old filename on line %d"), state->linenr);
free(another);
- return orig_name;
} else {
/* expect "/dev/null" */
if (memcmp("/dev/null", line, 9) || line[9] != '\n')
- die(_("git apply: bad git-diff - expected /dev/null on line %d"), linenr);
- return NULL;
+ die(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
}
}
-static int gitdiff_oldname(const char *line, struct patch *patch)
+static int gitdiff_oldname(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
- patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name,
- DIFF_OLD_NAME);
+ gitdiff_verify_name(state, line,
+ patch->is_new, &patch->old_name,
+ DIFF_OLD_NAME);
return 0;
}
-static int gitdiff_newname(const char *line, struct patch *patch)
+static int gitdiff_newname(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
- patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name,
- DIFF_NEW_NAME);
+ gitdiff_verify_name(state, line,
+ patch->is_delete, &patch->new_name,
+ DIFF_NEW_NAME);
return 0;
}
-static int gitdiff_oldmode(const char *line, struct patch *patch)
+static int gitdiff_oldmode(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->old_mode = strtoul(line, NULL, 8);
return 0;
}
-static int gitdiff_newmode(const char *line, struct patch *patch)
+static int gitdiff_newmode(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->new_mode = strtoul(line, NULL, 8);
return 0;
}
-static int gitdiff_delete(const char *line, struct patch *patch)
+static int gitdiff_delete(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->is_delete = 1;
free(patch->old_name);
patch->old_name = xstrdup_or_null(patch->def_name);
- return gitdiff_oldmode(line, patch);
+ return gitdiff_oldmode(state, line, patch);
}
-static int gitdiff_newfile(const char *line, struct patch *patch)
+static int gitdiff_newfile(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->is_new = 1;
free(patch->new_name);
patch->new_name = xstrdup_or_null(patch->def_name);
- return gitdiff_newmode(line, patch);
+ return gitdiff_newmode(state, line, patch);
}
-static int gitdiff_copysrc(const char *line, struct patch *patch)
+static int gitdiff_copysrc(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->is_copy = 1;
free(patch->old_name);
- patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+ patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
return 0;
}
-static int gitdiff_copydst(const char *line, struct patch *patch)
+static int gitdiff_copydst(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->is_copy = 1;
free(patch->new_name);
- patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+ patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
return 0;
}
-static int gitdiff_renamesrc(const char *line, struct patch *patch)
+static int gitdiff_renamesrc(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->is_rename = 1;
free(patch->old_name);
- patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+ patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
return 0;
}
-static int gitdiff_renamedst(const char *line, struct patch *patch)
+static int gitdiff_renamedst(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
patch->is_rename = 1;
free(patch->new_name);
- patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+ patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
return 0;
}
-static int gitdiff_similarity(const char *line, struct patch *patch)
+static int gitdiff_similarity(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
unsigned long val = strtoul(line, NULL, 10);
if (val <= 100)
@@ -1033,7 +1102,9 @@ static int gitdiff_similarity(const char *line, struct patch *patch)
return 0;
}
-static int gitdiff_dissimilarity(const char *line, struct patch *patch)
+static int gitdiff_dissimilarity(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
unsigned long val = strtoul(line, NULL, 10);
if (val <= 100)
@@ -1041,7 +1112,9 @@ static int gitdiff_dissimilarity(const char *line, struct patch *patch)
return 0;
}
-static int gitdiff_index(const char *line, struct patch *patch)
+static int gitdiff_index(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
/*
* index line is N hexadecimal, "..", N hexadecimal,
@@ -1078,7 +1151,9 @@ static int gitdiff_index(const char *line, struct patch *patch)
* This is normal for a diff that doesn't change anything: we'll fall through
* into the next diff. Tell the parser to break out.
*/
-static int gitdiff_unrecognized(const char *line, struct patch *patch)
+static int gitdiff_unrecognized(struct apply_state *state,
+ const char *line,
+ struct patch *patch)
{
return -1;
}
@@ -1087,15 +1162,17 @@ static int gitdiff_unrecognized(const char *line, struct patch *patch)
* Skip p_value leading components from "line"; as we do not accept
* absolute paths, return NULL in that case.
*/
-static const char *skip_tree_prefix(const char *line, int llen)
+static const char *skip_tree_prefix(struct apply_state *state,
+ const char *line,
+ int llen)
{
int nslash;
int i;
- if (!p_value)
+ if (!state->p_value)
return (llen && line[0] == '/') ? NULL : line;
- nslash = p_value;
+ nslash = state->p_value;
for (i = 0; i < llen; i++) {
int ch = line[i];
if (ch == '/' && --nslash <= 0)
@@ -1112,7 +1189,9 @@ static const char *skip_tree_prefix(const char *line, int llen)
* creation or deletion of an empty file. In any of these cases,
* both sides are the same name under a/ and b/ respectively.
*/
-static char *git_header_name(const char *line, int llen)
+static char *git_header_name(struct apply_state *state,
+ const char *line,
+ int llen)
{
const char *name;
const char *second = NULL;
@@ -1130,7 +1209,7 @@ static char *git_header_name(const char *line, int llen)
goto free_and_fail1;
/* strip the a/b prefix including trailing slash */
- cp = skip_tree_prefix(first.buf, first.len);
+ cp = skip_tree_prefix(state, first.buf, first.len);
if (!cp)
goto free_and_fail1;
strbuf_remove(&first, 0, cp - first.buf);
@@ -1147,7 +1226,7 @@ static char *git_header_name(const char *line, int llen)
if (*second == '"') {
if (unquote_c_style(&sp, second, NULL))
goto free_and_fail1;
- cp = skip_tree_prefix(sp.buf, sp.len);
+ cp = skip_tree_prefix(state, sp.buf, sp.len);
if (!cp)
goto free_and_fail1;
/* They must match, otherwise ignore */
@@ -1158,7 +1237,7 @@ static char *git_header_name(const char *line, int llen)
}
/* unquoted second */
- cp = skip_tree_prefix(second, line + llen - second);
+ cp = skip_tree_prefix(state, second, line + llen - second);
if (!cp)
goto free_and_fail1;
if (line + llen - cp != first.len ||
@@ -1173,7 +1252,7 @@ static char *git_header_name(const char *line, int llen)
}
/* unquoted first name */
- name = skip_tree_prefix(line, llen);
+ name = skip_tree_prefix(state, line, llen);
if (!name)
return NULL;
@@ -1189,7 +1268,7 @@ static char *git_header_name(const char *line, int llen)
if (unquote_c_style(&sp, second, NULL))
goto free_and_fail2;
- np = skip_tree_prefix(sp.buf, sp.len);
+ np = skip_tree_prefix(state, sp.buf, sp.len);
if (!np)
goto free_and_fail2;
@@ -1233,7 +1312,7 @@ static char *git_header_name(const char *line, int llen)
*/
if (!name[len + 1])
return NULL; /* no postimage name */
- second = skip_tree_prefix(name + len + 1,
+ second = skip_tree_prefix(state, name + len + 1,
line_len - (len + 1));
if (!second)
return NULL;
@@ -1249,7 +1328,11 @@ static char *git_header_name(const char *line, int llen)
}
/* Verify that we recognize the lines following a git header */
-static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
+static int parse_git_header(struct apply_state *state,
+ const char *line,
+ int len,
+ unsigned int size,
+ struct patch *patch)
{
unsigned long offset;
@@ -1263,20 +1346,20 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct
* or removing or adding empty files), so we get
* the default name from the header.
*/
- patch->def_name = git_header_name(line, len);
- if (patch->def_name && root.len) {
- char *s = xstrfmt("%s%s", root.buf, patch->def_name);
+ patch->def_name = git_header_name(state, line, len);
+ if (patch->def_name && state->root.len) {
+ char *s = xstrfmt("%s%s", state->root.buf, patch->def_name);
free(patch->def_name);
patch->def_name = s;
}
line += len;
size -= len;
- linenr++;
- for (offset = len ; size > 0 ; offset += len, size -= len, line += len, linenr++) {
+ state->linenr++;
+ for (offset = len ; size > 0 ; offset += len, size -= len, line += len, state->linenr++) {
static const struct opentry {
const char *str;
- int (*fn)(const char *, struct patch *);
+ int (*fn)(struct apply_state *, const char *, struct patch *);
} optable[] = {
{ "@@ -", gitdiff_hdrend },
{ "--- ", gitdiff_oldname },
@@ -1306,7 +1389,7 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct
int oplen = strlen(p->str);
if (len < oplen || memcmp(p->str, line, oplen))
continue;
- if (p->fn(line + oplen, patch) < 0)
+ if (p->fn(state, line + oplen, patch) < 0)
return offset;
break;
}
@@ -1431,7 +1514,11 @@ static int parse_fragment_header(const char *line, int len, struct fragment *fra
return offset;
}
-static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
+static int find_header(struct apply_state *state,
+ const char *line,
+ unsigned long size,
+ int *hdrsize,
+ struct patch *patch)
{
unsigned long offset, len;
@@ -1440,7 +1527,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
patch->is_new = patch->is_delete = -1;
patch->old_mode = patch->new_mode = 0;
patch->old_name = patch->new_name = NULL;
- for (offset = 0; size > 0; offset += len, size -= len, line += len, linenr++) {
+ for (offset = 0; size > 0; offset += len, size -= len, line += len, state->linenr++) {
unsigned long nextlen;
len = linelen(line, size);
@@ -1461,7 +1548,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
if (parse_fragment_header(line, len, &dummy) < 0)
continue;
die(_("patch fragment without header at line %d: %.*s"),
- linenr, (int)len-1, line);
+ state->linenr, (int)len-1, line);
}
if (size < len + 6)
@@ -1472,7 +1559,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
* or mode change, so we handle that specially
*/
if (!memcmp("diff --git ", line, 11)) {
- int git_hdr_len = parse_git_header(line, len, size, patch);
+ int git_hdr_len = parse_git_header(state, line, len, size, patch);
if (git_hdr_len <= len)
continue;
if (!patch->old_name && !patch->new_name) {
@@ -1481,14 +1568,14 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
"%d leading pathname component (line %d)",
"git diff header lacks filename information when removing "
"%d leading pathname components (line %d)",
- p_value),
- p_value, linenr);
+ state->p_value),
+ state->p_value, state->linenr);
patch->old_name = xstrdup(patch->def_name);
patch->new_name = xstrdup(patch->def_name);
}
if (!patch->is_delete && !patch->new_name)
die("git diff header lacks filename information "
- "(line %d)", linenr);
+ "(line %d)", state->linenr);
patch->is_toplevel_relative = 1;
*hdrsize = git_hdr_len;
return offset;
@@ -1508,37 +1595,44 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
continue;
/* Ok, we'll consider it a patch */
- parse_traditional_patch(line, line+len, patch);
+ parse_traditional_patch(state, line, line+len, patch);
*hdrsize = len + nextlen;
- linenr += 2;
+ state->linenr += 2;
return offset;
}
return -1;
}
-static void record_ws_error(unsigned result, const char *line, int len, int linenr)
+static void record_ws_error(struct apply_state *state,
+ unsigned result,
+ const char *line,
+ int len,
+ int linenr)
{
char *err;
if (!result)
return;
- whitespace_error++;
- if (squelch_whitespace_errors &&
- squelch_whitespace_errors < whitespace_error)
+ state->whitespace_error++;
+ if (state->squelch_whitespace_errors &&
+ state->squelch_whitespace_errors < state->whitespace_error)
return;
err = whitespace_error_string(result);
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
- patch_input_file, linenr, err, len, line);
+ state->patch_input_file, linenr, err, len, line);
free(err);
}
-static void check_whitespace(const char *line, int len, unsigned ws_rule)
+static void check_whitespace(struct apply_state *state,
+ const char *line,
+ int len,
+ unsigned ws_rule)
{
unsigned result = ws_check(line + 1, len - 1, ws_rule);
- record_ws_error(result, line + 1, len - 2, linenr);
+ record_ws_error(state, result, line + 1, len - 2, state->linenr);
}
/*
@@ -1547,8 +1641,11 @@ static void check_whitespace(const char *line, int len, unsigned ws_rule)
* between a "---" that is part of a patch, and a "---" that starts
* the next patch is to look at the line counts..
*/
-static int parse_fragment(const char *line, unsigned long size,
- struct patch *patch, struct fragment *fragment)
+static int parse_fragment(struct apply_state *state,
+ const char *line,
+ unsigned long size,
+ struct patch *patch,
+ struct fragment *fragment)
{
int added, deleted;
int len = linelen(line, size), offset;
@@ -1568,11 +1665,11 @@ static int parse_fragment(const char *line, unsigned long size,
/* Parse the thing.. */
line += len;
size -= len;
- linenr++;
+ state->linenr++;
added = deleted = 0;
for (offset = len;
0 < size;
- offset += len, size -= len, line += len, linenr++) {
+ offset += len, size -= len, line += len, state->linenr++) {
if (!oldlines && !newlines)
break;
len = linelen(line, size);
@@ -1588,22 +1685,22 @@ static int parse_fragment(const char *line, unsigned long size,
if (!deleted && !added)
leading++;
trailing++;
- if (!apply_in_reverse &&
- ws_error_action == correct_ws_error)
- check_whitespace(line, len, patch->ws_rule);
+ if (!state->apply_in_reverse &&
+ state->ws_error_action == correct_ws_error)
+ check_whitespace(state, line, len, patch->ws_rule);
break;
case '-':
- if (apply_in_reverse &&
- ws_error_action != nowarn_ws_error)
- check_whitespace(line, len, patch->ws_rule);
+ if (state->apply_in_reverse &&
+ state->ws_error_action != nowarn_ws_error)
+ check_whitespace(state, line, len, patch->ws_rule);
deleted++;
oldlines--;
trailing = 0;
break;
case '+':
- if (!apply_in_reverse &&
- ws_error_action != nowarn_ws_error)
- check_whitespace(line, len, patch->ws_rule);
+ if (!state->apply_in_reverse &&
+ state->ws_error_action != nowarn_ws_error)
+ check_whitespace(state, line, len, patch->ws_rule);
added++;
newlines--;
trailing = 0;
@@ -1657,7 +1754,10 @@ static int parse_fragment(const char *line, unsigned long size,
* The (fragment->patch, fragment->size) pair points into the memory given
* by the caller, not a copy, when we return.
*/
-static int parse_single_patch(const char *line, unsigned long size, struct patch *patch)
+static int parse_single_patch(struct apply_state *state,
+ const char *line,
+ unsigned long size,
+ struct patch *patch)
{
unsigned long offset = 0;
unsigned long oldlines = 0, newlines = 0, context = 0;
@@ -1668,10 +1768,10 @@ static int parse_single_patch(const char *line, unsigned long size, struct patch
int len;
fragment = xcalloc(1, sizeof(*fragment));
- fragment->linenr = linenr;
- len = parse_fragment(line, size, patch, fragment);
+ fragment->linenr = state->linenr;
+ len = parse_fragment(state, line, size, patch, fragment);
if (len <= 0)
- die(_("corrupt patch at line %d"), linenr);
+ die(_("corrupt patch at line %d"), state->linenr);
fragment->patch = line;
fragment->size = len;
oldlines += fragment->oldlines;
@@ -1757,7 +1857,8 @@ static char *inflate_it(const void *data, unsigned long size,
* points at an allocated memory that the caller must free, so
* it is marked as "->free_patch = 1".
*/
-static struct fragment *parse_binary_hunk(char **buf_p,
+static struct fragment *parse_binary_hunk(struct apply_state *state,
+ char **buf_p,
unsigned long *sz_p,
int *status_p,
int *used_p)
@@ -1799,13 +1900,13 @@ static struct fragment *parse_binary_hunk(char **buf_p,
else
return NULL;
- linenr++;
+ state->linenr++;
buffer += llen;
while (1) {
int byte_length, max_byte_length, newsize;
llen = linelen(buffer, size);
used += llen;
- linenr++;
+ state->linenr++;
if (llen == 1) {
/* consume the blank line */
buffer++;
@@ -1859,7 +1960,7 @@ static struct fragment *parse_binary_hunk(char **buf_p,
free(data);
*status_p = -1;
error(_("corrupt binary patch at line %d: %.*s"),
- linenr-1, llen-1, buffer);
+ state->linenr-1, llen-1, buffer);
return NULL;
}
@@ -1868,7 +1969,10 @@ static struct fragment *parse_binary_hunk(char **buf_p,
* -1 in case of error,
* the length of the parsed binary patch otherwise
*/
-static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+static int parse_binary(struct apply_state *state,
+ char *buffer,
+ unsigned long size,
+ struct patch *patch)
{
/*
* We have read "GIT binary patch\n"; what follows is a line
@@ -1889,15 +1993,15 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
int status;
int used, used_1;
- forward = parse_binary_hunk(&buffer, &size, &status, &used);
+ forward = parse_binary_hunk(state, &buffer, &size, &status, &used);
if (!forward && !status)
/* there has to be one hunk (forward hunk) */
- return error(_("unrecognized binary patch at line %d"), linenr-1);
+ return error(_("unrecognized binary patch at line %d"), state->linenr-1);
if (status)
/* otherwise we already gave an error message */
return status;
- reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
+ reverse = parse_binary_hunk(state, &buffer, &size, &status, &used_1);
if (reverse)
used += used_1;
else if (status) {
@@ -1915,53 +2019,53 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
return used;
}
-static void prefix_one(char **name)
+static void prefix_one(struct apply_state *state, char **name)
{
char *old_name = *name;
if (!old_name)
return;
- *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+ *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
free(old_name);
}
-static void prefix_patch(struct patch *p)
+static void prefix_patch(struct apply_state *state, struct patch *p)
{
- if (!prefix || p->is_toplevel_relative)
+ if (!state->prefix || p->is_toplevel_relative)
return;
- prefix_one(&p->new_name);
- prefix_one(&p->old_name);
+ prefix_one(state, &p->new_name);
+ prefix_one(state, &p->old_name);
}
/*
* include/exclude
*/
-static struct string_list limit_by_name;
-static int has_include;
-static void add_name_limit(const char *name, int exclude)
+static void add_name_limit(struct apply_state *state,
+ const char *name,
+ int exclude)
{
struct string_list_item *it;
- it = string_list_append(&limit_by_name, name);
+ it = string_list_append(&state->limit_by_name, name);
it->util = exclude ? NULL : (void *) 1;
}
-static int use_patch(struct patch *p)
+static int use_patch(struct apply_state *state, struct patch *p)
{
const char *pathname = p->new_name ? p->new_name : p->old_name;
int i;
/* Paths outside are not touched regardless of "--include" */
- if (0 < prefix_length) {
+ if (0 < state->prefix_length) {
int pathlen = strlen(pathname);
- if (pathlen <= prefix_length ||
- memcmp(prefix, pathname, prefix_length))
+ if (pathlen <= state->prefix_length ||
+ memcmp(state->prefix, pathname, state->prefix_length))
return 0;
}
/* See if it matches any of exclude/include rule */
- for (i = 0; i < limit_by_name.nr; i++) {
- struct string_list_item *it = &limit_by_name.items[i];
+ for (i = 0; i < state->limit_by_name.nr; i++) {
+ struct string_list_item *it = &state->limit_by_name.items[i];
if (!wildmatch(it->string, pathname, 0, NULL))
return (it->util != NULL);
}
@@ -1971,7 +2075,7 @@ static int use_patch(struct patch *p)
* not used. Otherwise, we saw bunch of exclude rules (or none)
* and such a path is used.
*/
- return !has_include;
+ return !state->has_include;
}
@@ -1982,25 +2086,27 @@ static int use_patch(struct patch *p)
* Return the number of bytes consumed, so that the caller can call us
* again for the next patch.
*/
-static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
+static int parse_chunk(struct apply_state *state, char *buffer, unsigned long size, struct patch *patch)
{
int hdrsize, patchsize;
- int offset = find_header(buffer, size, &hdrsize, patch);
+ int offset = find_header(state, buffer, size, &hdrsize, patch);
if (offset < 0)
return offset;
- prefix_patch(patch);
+ prefix_patch(state, patch);
- if (!use_patch(patch))
+ if (!use_patch(state, patch))
patch->ws_rule = 0;
else
patch->ws_rule = whitespace_rule(patch->new_name
? patch->new_name
: patch->old_name);
- patchsize = parse_single_patch(buffer + offset + hdrsize,
- size - offset - hdrsize, patch);
+ patchsize = parse_single_patch(state,
+ buffer + offset + hdrsize,
+ size - offset - hdrsize,
+ patch);
if (!patchsize) {
static const char git_binary[] = "GIT binary patch\n";
@@ -2010,8 +2116,8 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
if (llen == sizeof(git_binary) - 1 &&
!memcmp(git_binary, buffer + hd, llen)) {
int used;
- linenr++;
- used = parse_binary(buffer + hd + llen,
+ state->linenr++;
+ used = parse_binary(state, buffer + hd + llen,
size - hd - llen, patch);
if (used < 0)
return -1;
@@ -2031,7 +2137,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
int len = strlen(binhdr[i]);
if (len < size - hd &&
!memcmp(binhdr[i], buffer + hd, len)) {
- linenr++;
+ state->linenr++;
patch->is_binary = 1;
patchsize = llen;
break;
@@ -2043,9 +2149,9 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
* without metadata change. A binary patch appears
* empty to us here.
*/
- if ((apply || check) &&
+ if ((state->apply || state->check) &&
(!patch->is_binary && !metadata_changes(patch)))
- die(_("patch with only garbage at line %d"), linenr);
+ die(_("patch with only garbage at line %d"), state->linenr);
}
return offset + hdrsize + patchsize;
@@ -2083,7 +2189,7 @@ static const char pluses[] =
static const char minuses[]=
"----------------------------------------------------------------------";
-static void show_stats(struct patch *patch)
+static void show_stats(struct apply_state *state, struct patch *patch)
{
struct strbuf qname = STRBUF_INIT;
char *cp = patch->new_name ? patch->new_name : patch->old_name;
@@ -2094,7 +2200,7 @@ static void show_stats(struct patch *patch)
/*
* "scale" the filename
*/
- max = max_len;
+ max = state->max_len;
if (max > 50)
max = 50;
@@ -2117,13 +2223,13 @@ static void show_stats(struct patch *patch)
/*
* scale the add/delete
*/
- max = max + max_change > 70 ? 70 - max : max_change;
+ max = max + state->max_change > 70 ? 70 - max : state->max_change;
add = patch->lines_added;
del = patch->lines_deleted;
- if (max_change > 0) {
- int total = ((add + del) * max + max_change / 2) / max_change;
- add = (add * max + max_change / 2) / max_change;
+ if (state->max_change > 0) {
+ int total = ((add + del) * max + state->max_change / 2) / state->max_change;
+ add = (add * max + state->max_change / 2) / state->max_change;
del = total - add;
}
printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
@@ -2194,17 +2300,17 @@ static void update_pre_post_images(struct image *preimage,
fixed = preimage->buf;
for (i = reduced = ctx = 0; i < postimage->nr; i++) {
- size_t len = postimage->line[i].len;
+ size_t l_len = postimage->line[i].len;
if (!(postimage->line[i].flag & LINE_COMMON)) {
/* an added line -- no counterparts in preimage */
- memmove(new, old, len);
- old += len;
- new += len;
+ memmove(new, old, l_len);
+ old += l_len;
+ new += l_len;
continue;
}
/* a common context -- skip it in the original postimage */
- old += len;
+ old += l_len;
/* and find the corresponding one in the fixed preimage */
while (ctx < preimage->nr &&
@@ -2223,11 +2329,11 @@ static void update_pre_post_images(struct image *preimage,
}
/* and copy it in, while fixing the line length */
- len = preimage->line[ctx].len;
- memcpy(new, fixed, len);
- new += len;
- fixed += len;
- postimage->line[i].len = len;
+ l_len = preimage->line[ctx].len;
+ memcpy(new, fixed, l_len);
+ new += l_len;
+ fixed += l_len;
+ postimage->line[i].len = l_len;
ctx++;
}
@@ -2242,7 +2348,76 @@ static void update_pre_post_images(struct image *preimage,
postimage->nr -= reduced;
}
-static int match_fragment(struct image *img,
+static int line_by_line_fuzzy_match(struct image *img,
+ struct image *preimage,
+ struct image *postimage,
+ unsigned long try,
+ int try_lno,
+ int preimage_limit)
+{
+ int i;
+ size_t imgoff = 0;
+ size_t preoff = 0;
+ size_t postlen = postimage->len;
+ size_t extra_chars;
+ char *buf;
+ char *preimage_eof;
+ char *preimage_end;
+ struct strbuf fixed;
+ char *fixed_buf;
+ size_t fixed_len;
+
+ for (i = 0; i < preimage_limit; i++) {
+ size_t prelen = preimage->line[i].len;
+ size_t imglen = img->line[try_lno+i].len;
+
+ if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
+ preimage->buf + preoff, prelen))
+ return 0;
+ if (preimage->line[i].flag & LINE_COMMON)
+ postlen += imglen - prelen;
+ imgoff += imglen;
+ preoff += prelen;
+ }
+
+ /*
+ * Ok, the preimage matches with whitespace fuzz.
+ *
+ * imgoff now holds the true length of the target that
+ * matches the preimage before the end of the file.
+ *
+ * Count the number of characters in the preimage that fall
+ * beyond the end of the file and make sure that all of them
+ * are whitespace characters. (This can only happen if
+ * we are removing blank lines at the end of the file.)
+ */
+ buf = preimage_eof = preimage->buf + preoff;
+ for ( ; i < preimage->nr; i++)
+ preoff += preimage->line[i].len;
+ preimage_end = preimage->buf + preoff;
+ for ( ; buf < preimage_end; buf++)
+ if (!isspace(*buf))
+ return 0;
+
+ /*
+ * Update the preimage and the common postimage context
+ * lines to use the same whitespace as the target.
+ * If whitespace is missing in the target (i.e.
+ * if the preimage extends beyond the end of the file),
+ * use the whitespace from the preimage.
+ */
+ extra_chars = preimage_end - preimage_eof;
+ strbuf_init(&fixed, imgoff + extra_chars);
+ strbuf_add(&fixed, img->buf + try, imgoff);
+ strbuf_add(&fixed, preimage_eof, extra_chars);
+ fixed_buf = strbuf_detach(&fixed, &fixed_len);
+ update_pre_post_images(preimage, postimage,
+ fixed_buf, fixed_len, postlen);
+ return 1;
+}
+
+static int match_fragment(struct apply_state *state,
+ struct image *img,
struct image *preimage,
struct image *postimage,
unsigned long try,
@@ -2263,7 +2438,7 @@ static int match_fragment(struct image *img,
preimage_limit = preimage->nr;
if (match_end && (preimage->nr + try_lno != img->nr))
return 0;
- } else if (ws_error_action == correct_ws_error &&
+ } else if (state->ws_error_action == correct_ws_error &&
(ws_rule & WS_BLANK_AT_EOF)) {
/*
* This hunk extends beyond the end of img, and we are
@@ -2331,63 +2506,11 @@ static int match_fragment(struct image *img,
* fuzzy matching. We collect all the line length information because
* we need it to adjust whitespace if we match.
*/
- if (ws_ignore_action == ignore_ws_change) {
- size_t imgoff = 0;
- size_t preoff = 0;
- size_t postlen = postimage->len;
- size_t extra_chars;
- char *preimage_eof;
- char *preimage_end;
- for (i = 0; i < preimage_limit; i++) {
- size_t prelen = preimage->line[i].len;
- size_t imglen = img->line[try_lno+i].len;
-
- if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
- preimage->buf + preoff, prelen))
- return 0;
- if (preimage->line[i].flag & LINE_COMMON)
- postlen += imglen - prelen;
- imgoff += imglen;
- preoff += prelen;
- }
+ if (state->ws_ignore_action == ignore_ws_change)
+ return line_by_line_fuzzy_match(img, preimage, postimage,
+ try, try_lno, preimage_limit);
- /*
- * Ok, the preimage matches with whitespace fuzz.
- *
- * imgoff now holds the true length of the target that
- * matches the preimage before the end of the file.
- *
- * Count the number of characters in the preimage that fall
- * beyond the end of the file and make sure that all of them
- * are whitespace characters. (This can only happen if
- * we are removing blank lines at the end of the file.)
- */
- buf = preimage_eof = preimage->buf + preoff;
- for ( ; i < preimage->nr; i++)
- preoff += preimage->line[i].len;
- preimage_end = preimage->buf + preoff;
- for ( ; buf < preimage_end; buf++)
- if (!isspace(*buf))
- return 0;
-
- /*
- * Update the preimage and the common postimage context
- * lines to use the same whitespace as the target.
- * If whitespace is missing in the target (i.e.
- * if the preimage extends beyond the end of the file),
- * use the whitespace from the preimage.
- */
- extra_chars = preimage_end - preimage_eof;
- strbuf_init(&fixed, imgoff + extra_chars);
- strbuf_add(&fixed, img->buf + try, imgoff);
- strbuf_add(&fixed, preimage_eof, extra_chars);
- fixed_buf = strbuf_detach(&fixed, &fixed_len);
- update_pre_post_images(preimage, postimage,
- fixed_buf, fixed_len, postlen);
- return 1;
- }
-
- if (ws_error_action != correct_ws_error)
+ if (state->ws_error_action != correct_ws_error)
return 0;
/*
@@ -2499,7 +2622,8 @@ static int match_fragment(struct image *img,
return 0;
}
-static int find_pos(struct image *img,
+static int find_pos(struct apply_state *state,
+ struct image *img,
struct image *preimage,
struct image *postimage,
int line,
@@ -2543,7 +2667,7 @@ static int find_pos(struct image *img,
try_lno = line;
for (i = 0; ; i++) {
- if (match_fragment(img, preimage, postimage,
+ if (match_fragment(state, img, preimage, postimage,
try, try_lno, ws_rule,
match_beginning, match_end))
return try_lno;
@@ -2594,7 +2718,8 @@ static void remove_last_line(struct image *img)
* apply at applied_pos (counts in line numbers) in "img".
* Update "img" to remove "preimage" and replace it with "postimage".
*/
-static void update_image(struct image *img,
+static void update_image(struct apply_state *state,
+ struct image *img,
int applied_pos,
struct image *preimage,
struct image *postimage)
@@ -2659,7 +2784,7 @@ static void update_image(struct image *img,
memcpy(img->line + applied_pos,
postimage->line,
postimage->nr * sizeof(*img->line));
- if (!allow_overlap)
+ if (!state->allow_overlap)
for (i = 0; i < postimage->nr; i++)
img->line[applied_pos + i].flag |= LINE_PATCHED;
img->nr = nr;
@@ -2670,7 +2795,8 @@ static void update_image(struct image *img,
* postimage) for the hunk. Find lines that match "preimage" in "img" and
* replace the part of "img" with "postimage" text.
*/
-static int apply_one_fragment(struct image *img, struct fragment *frag,
+static int apply_one_fragment(struct apply_state *state,
+ struct image *img, struct fragment *frag,
int inaccurate_eof, unsigned ws_rule,
int nth_fragment)
{
@@ -2715,7 +2841,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
if (len < size && patch[len] == '\\')
plen--;
first = *patch;
- if (apply_in_reverse) {
+ if (state->apply_in_reverse) {
if (first == '-')
first = '+';
else if (first == '+')
@@ -2748,17 +2874,17 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
/* Fall-through for ' ' */
case '+':
/* --no-add does not add new lines */
- if (first == '+' && no_add)
+ if (first == '+' && state->no_add)
break;
start = newlines.len;
if (first != '+' ||
- !whitespace_error ||
- ws_error_action != correct_ws_error) {
+ !state->whitespace_error ||
+ state->ws_error_action != correct_ws_error) {
strbuf_add(&newlines, patch + 1, plen);
}
else {
- ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
+ ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &state->applied_after_fixing_ws);
}
add_line_info(&postimage, newlines.buf + start, newlines.len - start,
(first == '+' ? 0 : LINE_COMMON));
@@ -2771,7 +2897,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
/* Ignore it, we already handled it */
break;
default:
- if (apply_verbosely)
+ if (state->apply_verbosely)
error(_("invalid start of line: '%c'"), first);
applied_pos = -1;
goto out;
@@ -2812,7 +2938,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
* without leading context must match at the beginning.
*/
match_beginning = (!frag->oldpos ||
- (frag->oldpos == 1 && !unidiff_zero));
+ (frag->oldpos == 1 && !state->unidiff_zero));
/*
* A hunk without trailing lines must match at the end.
@@ -2820,7 +2946,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
* from the lack of trailing lines if the patch was generated
* with unidiff without any context.
*/
- match_end = !unidiff_zero && !trailing;
+ match_end = !state->unidiff_zero && !trailing;
pos = frag->newpos ? (frag->newpos - 1) : 0;
preimage.buf = oldlines;
@@ -2832,14 +2958,14 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
for (;;) {
- applied_pos = find_pos(img, &preimage, &postimage, pos,
+ applied_pos = find_pos(state, img, &preimage, &postimage, pos,
ws_rule, match_beginning, match_end);
if (applied_pos >= 0)
break;
/* Am I at my context limits? */
- if ((leading <= p_context) && (trailing <= p_context))
+ if ((leading <= state->p_context) && (trailing <= state->p_context))
break;
if (match_beginning || match_end) {
match_beginning = match_end = 0;
@@ -2868,10 +2994,10 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
if (new_blank_lines_at_end &&
preimage.nr + applied_pos >= img->nr &&
(ws_rule & WS_BLANK_AT_EOF) &&
- ws_error_action != nowarn_ws_error) {
- record_ws_error(WS_BLANK_AT_EOF, "+", 1,
+ state->ws_error_action != nowarn_ws_error) {
+ record_ws_error(state, WS_BLANK_AT_EOF, "+", 1,
found_new_blank_lines_at_end);
- if (ws_error_action == correct_ws_error) {
+ if (state->ws_error_action == correct_ws_error) {
while (new_blank_lines_at_end--)
remove_last_line(&postimage);
}
@@ -2882,13 +3008,13 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
* apply_patch->check_patch_list->check_patch->
* apply_data->apply_fragments->apply_one_fragment
*/
- if (ws_error_action == die_on_ws_error)
- apply = 0;
+ if (state->ws_error_action == die_on_ws_error)
+ state->apply = 0;
}
- if (apply_verbosely && applied_pos != pos) {
+ if (state->apply_verbosely && applied_pos != pos) {
int offset = applied_pos - pos;
- if (apply_in_reverse)
+ if (state->apply_in_reverse)
offset = 0 - offset;
fprintf_ln(stderr,
Q_("Hunk #%d succeeded at %d (offset %d line).",
@@ -2906,9 +3032,9 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
fprintf_ln(stderr, _("Context reduced to (%ld/%ld)"
" to apply fragment at %d"),
leading, trailing, applied_pos+1);
- update_image(img, applied_pos, &preimage, &postimage);
+ update_image(state, img, applied_pos, &preimage, &postimage);
} else {
- if (apply_verbosely)
+ if (state->apply_verbosely)
error(_("while searching for:\n%.*s"),
(int)(old - oldlines), oldlines);
}
@@ -2922,7 +3048,9 @@ out:
return (applied_pos < 0);
}
-static int apply_binary_fragment(struct image *img, struct patch *patch)
+static int apply_binary_fragment(struct apply_state *state,
+ struct image *img,
+ struct patch *patch)
{
struct fragment *fragment = patch->fragments;
unsigned long len;
@@ -2935,7 +3063,7 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
patch->old_name);
/* Binary patch is irreversible without the optional second hunk */
- if (apply_in_reverse) {
+ if (state->apply_in_reverse) {
if (!fragment->next)
return error("cannot reverse-apply a binary patch "
"without the reverse hunk to '%s'",
@@ -2968,7 +3096,9 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
* but the preimage prepared by the caller in "img" is freed here
* or in the helper function apply_binary_fragment() this calls.
*/
-static int apply_binary(struct image *img, struct patch *patch)
+static int apply_binary(struct apply_state *state,
+ struct image *img,
+ struct patch *patch)
{
const char *name = patch->old_name ? patch->old_name : patch->new_name;
unsigned char sha1[20];
@@ -3029,7 +3159,7 @@ static int apply_binary(struct image *img, struct patch *patch)
* apply the patch data to it, which is stored
* in the patch->fragments->{patch,size}.
*/
- if (apply_binary_fragment(img, patch))
+ if (apply_binary_fragment(state, img, patch))
return error(_("binary patch does not apply to '%s'"),
name);
@@ -3043,7 +3173,7 @@ static int apply_binary(struct image *img, struct patch *patch)
return 0;
}
-static int apply_fragments(struct image *img, struct patch *patch)
+static int apply_fragments(struct apply_state *state, struct image *img, struct patch *patch)
{
struct fragment *frag = patch->fragments;
const char *name = patch->old_name ? patch->old_name : patch->new_name;
@@ -3052,13 +3182,13 @@ static int apply_fragments(struct image *img, struct patch *patch)
int nth = 0;
if (patch->is_binary)
- return apply_binary(img, patch);
+ return apply_binary(state, img, patch);
while (frag) {
nth++;
- if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
+ if (apply_one_fragment(state, img, frag, inaccurate_eof, ws_rule, nth)) {
error(_("patch failed: %s:%ld"), name, frag->oldpos);
- if (!apply_with_reject)
+ if (!state->apply_with_reject)
return -1;
frag->rejected = 1;
}
@@ -3093,14 +3223,14 @@ static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf
return read_blob_object(buf, ce->sha1, ce->ce_mode);
}
-static struct patch *in_fn_table(const char *name)
+static struct patch *in_fn_table(struct apply_state *state, const char *name)
{
struct string_list_item *item;
if (name == NULL)
return NULL;
- item = string_list_lookup(&fn_table, name);
+ item = string_list_lookup(&state->fn_table, name);
if (item != NULL)
return (struct patch *)item->util;
@@ -3132,7 +3262,7 @@ static int was_deleted(struct patch *patch)
return patch == PATH_WAS_DELETED;
}
-static void add_to_fn_table(struct patch *patch)
+static void add_to_fn_table(struct apply_state *state, struct patch *patch)
{
struct string_list_item *item;
@@ -3142,7 +3272,7 @@ static void add_to_fn_table(struct patch *patch)
* file creations and copies
*/
if (patch->new_name != NULL) {
- item = string_list_insert(&fn_table, patch->new_name);
+ item = string_list_insert(&state->fn_table, patch->new_name);
item->util = patch;
}
@@ -3151,12 +3281,12 @@ static void add_to_fn_table(struct patch *patch)
* later chunks shouldn't patch old names
*/
if ((patch->new_name == NULL) || (patch->is_rename)) {
- item = string_list_insert(&fn_table, patch->old_name);
+ item = string_list_insert(&state->fn_table, patch->old_name);
item->util = PATH_WAS_DELETED;
}
}
-static void prepare_fn_table(struct patch *patch)
+static void prepare_fn_table(struct apply_state *state, struct patch *patch)
{
/*
* store information about incoming file deletion
@@ -3164,7 +3294,7 @@ static void prepare_fn_table(struct patch *patch)
while (patch) {
if ((patch->new_name == NULL) || (patch->is_rename)) {
struct string_list_item *item;
- item = string_list_insert(&fn_table, patch->old_name);
+ item = string_list_insert(&state->fn_table, patch->old_name);
item->util = PATH_TO_BE_DELETED;
}
patch = patch->next;
@@ -3185,7 +3315,9 @@ static int checkout_target(struct index_state *istate,
return 0;
}
-static struct patch *previous_patch(struct patch *patch, int *gone)
+static struct patch *previous_patch(struct apply_state *state,
+ struct patch *patch,
+ int *gone)
{
struct patch *previous;
@@ -3193,7 +3325,7 @@ static struct patch *previous_patch(struct patch *patch, int *gone)
if (patch->is_copy || patch->is_rename)
return NULL; /* "git" patches do not depend on the order */
- previous = in_fn_table(patch->old_name);
+ previous = in_fn_table(state, patch->old_name);
if (!previous)
return NULL;
@@ -3218,13 +3350,14 @@ static int verify_index_match(const struct cache_entry *ce, struct stat *st)
#define SUBMODULE_PATCH_WITHOUT_INDEX 1
-static int load_patch_target(struct strbuf *buf,
+static int load_patch_target(struct apply_state *state,
+ struct strbuf *buf,
const struct cache_entry *ce,
struct stat *st,
const char *name,
unsigned expected_mode)
{
- if (cached || check_index) {
+ if (state->cached || state->check_index) {
if (read_file_or_gitlink(ce, buf))
return error(_("failed to read %s"), name);
} else if (name) {
@@ -3250,7 +3383,8 @@ static int load_patch_target(struct strbuf *buf,
* applying a non-git patch that incrementally updates the tree,
* we read from the result of a previous diff.
*/
-static int load_preimage(struct image *image,
+static int load_preimage(struct apply_state *state,
+ struct image *image,
struct patch *patch, struct stat *st,
const struct cache_entry *ce)
{
@@ -3260,7 +3394,7 @@ static int load_preimage(struct image *image,
struct patch *previous;
int status;
- previous = previous_patch(patch, &status);
+ previous = previous_patch(state, patch, &status);
if (status)
return error(_("path %s has been renamed/deleted"),
patch->old_name);
@@ -3268,7 +3402,7 @@ static int load_preimage(struct image *image,
/* We have a patched copy in memory; use that. */
strbuf_add(&buf, previous->result, previous->resultsize);
} else {
- status = load_patch_target(&buf, ce, st,
+ status = load_patch_target(state, &buf, ce, st,
patch->old_name, patch->old_mode);
if (status < 0)
return status;
@@ -3327,7 +3461,9 @@ static int three_way_merge(struct image *image,
* the current contents of the new_name. In no cases other than that
* this function will be called.
*/
-static int load_current(struct image *image, struct patch *patch)
+static int load_current(struct apply_state *state,
+ struct image *image,
+ struct patch *patch)
{
struct strbuf buf = STRBUF_INIT;
int status, pos;
@@ -3354,7 +3490,7 @@ static int load_current(struct image *image, struct patch *patch)
if (verify_index_match(ce, &st))
return error(_("%s: does not match index"), name);
- status = load_patch_target(&buf, ce, &st, name, mode);
+ status = load_patch_target(state, &buf, ce, &st, name, mode);
if (status < 0)
return status;
else if (status)
@@ -3364,8 +3500,11 @@ static int load_current(struct image *image, struct patch *patch)
return 0;
}
-static int try_threeway(struct image *image, struct patch *patch,
- struct stat *st, const struct cache_entry *ce)
+static int try_threeway(struct apply_state *state,
+ struct image *image,
+ struct patch *patch,
+ struct stat *st,
+ const struct cache_entry *ce)
{
unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
struct strbuf buf = STRBUF_INIT;
@@ -3391,7 +3530,7 @@ static int try_threeway(struct image *image, struct patch *patch,
img = strbuf_detach(&buf, &len);
prepare_image(&tmp_image, img, len, 1);
/* Apply the patch to get the post image */
- if (apply_fragments(&tmp_image, patch) < 0) {
+ if (apply_fragments(state, &tmp_image, patch) < 0) {
clear_image(&tmp_image);
return -1;
}
@@ -3401,11 +3540,11 @@ static int try_threeway(struct image *image, struct patch *patch,
/* our_sha1[] is ours */
if (patch->is_new) {
- if (load_current(&tmp_image, patch))
+ if (load_current(state, &tmp_image, patch))
return error("cannot read the current contents of '%s'",
patch->new_name);
} else {
- if (load_preimage(&tmp_image, patch, st, ce))
+ if (load_preimage(state, &tmp_image, patch, st, ce))
return error("cannot read the current contents of '%s'",
patch->old_name);
}
@@ -3435,22 +3574,23 @@ static int try_threeway(struct image *image, struct patch *patch,
return 0;
}
-static int apply_data(struct patch *patch, struct stat *st, const struct cache_entry *ce)
+static int apply_data(struct apply_state *state, struct patch *patch,
+ struct stat *st, const struct cache_entry *ce)
{
struct image image;
- if (load_preimage(&image, patch, st, ce) < 0)
+ if (load_preimage(state, &image, patch, st, ce) < 0)
return -1;
if (patch->direct_to_threeway ||
- apply_fragments(&image, patch) < 0) {
+ apply_fragments(state, &image, patch) < 0) {
/* Note: with --reject, apply_fragments() returns 0 */
- if (!threeway || try_threeway(&image, patch, st, ce) < 0)
+ if (!state->threeway || try_threeway(state, &image, patch, st, ce) < 0)
return -1;
}
patch->result = image.buf;
patch->resultsize = image.len;
- add_to_fn_table(patch);
+ add_to_fn_table(state, patch);
free(image.line_allocated);
if (0 < patch->is_delete && patch->resultsize)
@@ -3470,7 +3610,10 @@ static int apply_data(struct patch *patch, struct stat *st, const struct cache_e
* check_patch() separately makes sure (and errors out otherwise) that
* the path the patch creates does not exist in the current tree.
*/
-static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
+static int check_preimage(struct apply_state *state,
+ struct patch *patch,
+ struct cache_entry **ce,
+ struct stat *st)
{
const char *old_name = patch->old_name;
struct patch *previous = NULL;
@@ -3481,19 +3624,19 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
return 0;
assert(patch->is_new <= 0);
- previous = previous_patch(patch, &status);
+ previous = previous_patch(state, patch, &status);
if (status)
return error(_("path %s has been renamed/deleted"), old_name);
if (previous) {
st_mode = previous->new_mode;
- } else if (!cached) {
+ } else if (!state->cached) {
stat_ret = lstat(old_name, st);
if (stat_ret && errno != ENOENT)
return error(_("%s: %s"), old_name, strerror(errno));
}
- if (check_index && !previous) {
+ if (state->check_index && !previous) {
int pos = cache_name_pos(old_name, strlen(old_name));
if (pos < 0) {
if (patch->is_new < 0)
@@ -3505,9 +3648,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
if (checkout_target(&the_index, *ce, st))
return -1;
}
- if (!cached && verify_index_match(*ce, st))
+ if (!state->cached && verify_index_match(*ce, st))
return error(_("%s: does not match index"), old_name);
- if (cached)
+ if (state->cached)
st_mode = (*ce)->ce_mode;
} else if (stat_ret < 0) {
if (patch->is_new < 0)
@@ -3515,7 +3658,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
return error(_("%s: %s"), old_name, strerror(errno));
}
- if (!cached && !previous)
+ if (!state->cached && !previous)
st_mode = ce_mode_from_stat(*ce, st->st_mode);
if (patch->is_new < 0)
@@ -3543,15 +3686,17 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
#define EXISTS_IN_INDEX 1
#define EXISTS_IN_WORKTREE 2
-static int check_to_create(const char *new_name, int ok_if_exists)
+static int check_to_create(struct apply_state *state,
+ const char *new_name,
+ int ok_if_exists)
{
struct stat nst;
- if (check_index &&
+ if (state->check_index &&
cache_name_pos(new_name, strlen(new_name)) >= 0 &&
!ok_if_exists)
return EXISTS_IN_INDEX;
- if (cached)
+ if (state->cached)
return 0;
if (!lstat(new_name, &nst)) {
@@ -3574,56 +3719,46 @@ static int check_to_create(const char *new_name, int ok_if_exists)
return 0;
}
-/*
- * We need to keep track of how symlinks in the preimage are
- * manipulated by the patches. A patch to add a/b/c where a/b
- * is a symlink should not be allowed to affect the directory
- * the symlink points at, but if the same patch removes a/b,
- * it is perfectly fine, as the patch removes a/b to make room
- * to create a directory a/b so that a/b/c can be created.
- */
-static struct string_list symlink_changes;
-#define SYMLINK_GOES_AWAY 01
-#define SYMLINK_IN_RESULT 02
-
-static uintptr_t register_symlink_changes(const char *path, uintptr_t what)
+static uintptr_t register_symlink_changes(struct apply_state *state,
+ const char *path,
+ uintptr_t what)
{
struct string_list_item *ent;
- ent = string_list_lookup(&symlink_changes, path);
+ ent = string_list_lookup(&state->symlink_changes, path);
if (!ent) {
- ent = string_list_insert(&symlink_changes, path);
+ ent = string_list_insert(&state->symlink_changes, path);
ent->util = (void *)0;
}
ent->util = (void *)(what | ((uintptr_t)ent->util));
return (uintptr_t)ent->util;
}
-static uintptr_t check_symlink_changes(const char *path)
+static uintptr_t check_symlink_changes(struct apply_state *state, const char *path)
{
struct string_list_item *ent;
- ent = string_list_lookup(&symlink_changes, path);
+ ent = string_list_lookup(&state->symlink_changes, path);
if (!ent)
return 0;
return (uintptr_t)ent->util;
}
-static void prepare_symlink_changes(struct patch *patch)
+static void prepare_symlink_changes(struct apply_state *state, struct patch *patch)
{
for ( ; patch; patch = patch->next) {
if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
(patch->is_rename || patch->is_delete))
/* the symlink at patch->old_name is removed */
- register_symlink_changes(patch->old_name, SYMLINK_GOES_AWAY);
+ register_symlink_changes(state, patch->old_name, SYMLINK_GOES_AWAY);
if (patch->new_name && S_ISLNK(patch->new_mode))
/* the symlink at patch->new_name is created or remains */
- register_symlink_changes(patch->new_name, SYMLINK_IN_RESULT);
+ register_symlink_changes(state, patch->new_name, SYMLINK_IN_RESULT);
}
}
-static int path_is_beyond_symlink_1(struct strbuf *name)
+static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *name)
{
do {
unsigned int change;
@@ -3633,7 +3768,7 @@ static int path_is_beyond_symlink_1(struct strbuf *name)
if (!name->len)
break;
name->buf[name->len] = '\0';
- change = check_symlink_changes(name->buf);
+ change = check_symlink_changes(state, name->buf);
if (change & SYMLINK_IN_RESULT)
return 1;
if (change & SYMLINK_GOES_AWAY)
@@ -3644,7 +3779,7 @@ static int path_is_beyond_symlink_1(struct strbuf *name)
continue;
/* otherwise, check the preimage */
- if (check_index) {
+ if (state->check_index) {
struct cache_entry *ce;
ce = cache_file_exists(name->buf, name->len, ignore_case);
@@ -3659,14 +3794,14 @@ static int path_is_beyond_symlink_1(struct strbuf *name)
return 0;
}
-static int path_is_beyond_symlink(const char *name_)
+static int path_is_beyond_symlink(struct apply_state *state, const char *name_)
{
int ret;
struct strbuf name = STRBUF_INIT;
assert(*name_ != '\0');
strbuf_addstr(&name, name_);
- ret = path_is_beyond_symlink_1(&name);
+ ret = path_is_beyond_symlink_1(state, &name);
strbuf_release(&name);
return ret;
@@ -3693,7 +3828,7 @@ static void die_on_unsafe_path(struct patch *patch)
* Check and apply the patch in-core; leave the result in patch->result
* for the caller to write it out to the final destination.
*/
-static int check_patch(struct patch *patch)
+static int check_patch(struct apply_state *state, struct patch *patch)
{
struct stat st;
const char *old_name = patch->old_name;
@@ -3706,7 +3841,7 @@ static int check_patch(struct patch *patch)
patch->rejected = 1; /* we will drop this after we succeed */
- status = check_preimage(patch, &ce, &st);
+ status = check_preimage(state, patch, &ce, &st);
if (status)
return status;
old_name = patch->old_name;
@@ -3725,7 +3860,7 @@ static int check_patch(struct patch *patch)
* B and rename from A to B is handled the same way by asking
* was_deleted().
*/
- if ((tpatch = in_fn_table(new_name)) &&
+ if ((tpatch = in_fn_table(state, new_name)) &&
(was_deleted(tpatch) || to_be_deleted(tpatch)))
ok_if_exists = 1;
else
@@ -3733,9 +3868,9 @@ static int check_patch(struct patch *patch)
if (new_name &&
((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
- int err = check_to_create(new_name, ok_if_exists);
+ int err = check_to_create(state, new_name, ok_if_exists);
- if (err && threeway) {
+ if (err && state->threeway) {
patch->direct_to_threeway = 1;
} else switch (err) {
case 0:
@@ -3776,7 +3911,7 @@ static int check_patch(struct patch *patch)
}
}
- if (!unsafe_paths)
+ if (!state->unsafe_paths)
die_on_unsafe_path(patch);
/*
@@ -3788,27 +3923,27 @@ static int check_patch(struct patch *patch)
* is not deposited to a path that is beyond a symbolic link
* here.
*/
- if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
+ if (!patch->is_delete && path_is_beyond_symlink(state, patch->new_name))
return error(_("affected file '%s' is beyond a symbolic link"),
patch->new_name);
- if (apply_data(patch, &st, ce) < 0)
+ if (apply_data(state, patch, &st, ce) < 0)
return error(_("%s: patch does not apply"), name);
patch->rejected = 0;
return 0;
}
-static int check_patch_list(struct patch *patch)
+static int check_patch_list(struct apply_state *state, struct patch *patch)
{
int err = 0;
- prepare_symlink_changes(patch);
- prepare_fn_table(patch);
+ prepare_symlink_changes(state, patch);
+ prepare_fn_table(state, patch);
while (patch) {
- if (apply_verbosely)
+ if (state->apply_verbosely)
say_patch_name(stderr,
_("Checking patch %s..."), patch);
- err |= check_patch(patch);
+ err |= check_patch(state, patch);
patch = patch->next;
}
return err;
@@ -3912,7 +4047,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
discard_index(&result);
}
-static void stat_patch_list(struct patch *patch)
+static void stat_patch_list(struct apply_state *state, struct patch *patch)
{
int files, adds, dels;
@@ -3920,13 +4055,14 @@ static void stat_patch_list(struct patch *patch)
files++;
adds += patch->lines_added;
dels += patch->lines_deleted;
- show_stats(patch);
+ show_stats(state, patch);
}
print_stat_summary(stdout, files, adds, dels);
}
-static void numstat_patch_list(struct patch *patch)
+static void numstat_patch_list(struct apply_state *state,
+ struct patch *patch)
{
for ( ; patch; patch = patch->next) {
const char *name;
@@ -3935,7 +4071,7 @@ static void numstat_patch_list(struct patch *patch)
printf("-\t-\t");
else
printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
- write_name_quoted(name, stdout, line_termination);
+ write_name_quoted(name, stdout, state->line_termination);
}
}
@@ -4017,49 +4153,53 @@ static void summary_patch_list(struct patch *patch)
}
}
-static void patch_stats(struct patch *patch)
+static void patch_stats(struct apply_state *state, struct patch *patch)
{
int lines = patch->lines_added + patch->lines_deleted;
- if (lines > max_change)
- max_change = lines;
+ if (lines > state->max_change)
+ state->max_change = lines;
if (patch->old_name) {
int len = quote_c_style(patch->old_name, NULL, NULL, 0);
if (!len)
len = strlen(patch->old_name);
- if (len > max_len)
- max_len = len;
+ if (len > state->max_len)
+ state->max_len = len;
}
if (patch->new_name) {
int len = quote_c_style(patch->new_name, NULL, NULL, 0);
if (!len)
len = strlen(patch->new_name);
- if (len > max_len)
- max_len = len;
+ if (len > state->max_len)
+ state->max_len = len;
}
}
-static void remove_file(struct patch *patch, int rmdir_empty)
+static void remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
{
- if (update_index) {
+ if (state->update_index) {
if (remove_file_from_cache(patch->old_name) < 0)
die(_("unable to remove %s from index"), patch->old_name);
}
- if (!cached) {
+ if (!state->cached) {
if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
}
-static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
+static void add_index_file(struct apply_state *state,
+ const char *path,
+ unsigned mode,
+ void *buf,
+ unsigned long size)
{
struct stat st;
struct cache_entry *ce;
int namelen = strlen(path);
unsigned ce_size = cache_entry_size(namelen);
- if (!update_index)
+ if (!state->update_index)
return;
ce = xcalloc(1, ce_size);
@@ -4074,7 +4214,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
get_sha1_hex(s, ce->sha1))
die(_("corrupt patch for submodule %s"), path);
} else {
- if (!cached) {
+ if (!state->cached) {
if (lstat(path, &st) < 0)
die_errno(_("unable to stat newly created file '%s'"),
path);
@@ -4126,9 +4266,13 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
* which is true 99% of the time anyway. If they don't,
* we create them and try again.
*/
-static void create_one_file(char *path, unsigned mode, const char *buf, unsigned long size)
+static void create_one_file(struct apply_state *state,
+ char *path,
+ unsigned mode,
+ const char *buf,
+ unsigned long size)
{
- if (cached)
+ if (state->cached)
return;
if (!try_create_file(path, mode, buf, size))
return;
@@ -4169,13 +4313,14 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
die_errno(_("unable to write file '%s' mode %o"), path, mode);
}
-static void add_conflicted_stages_file(struct patch *patch)
+static void add_conflicted_stages_file(struct apply_state *state,
+ struct patch *patch)
{
int stage, namelen;
unsigned ce_size, mode;
struct cache_entry *ce;
- if (!update_index)
+ if (!state->update_index)
return;
namelen = strlen(patch->new_name);
ce_size = cache_entry_size(namelen);
@@ -4196,7 +4341,7 @@ static void add_conflicted_stages_file(struct patch *patch)
}
}
-static void create_file(struct patch *patch)
+static void create_file(struct apply_state *state, struct patch *patch)
{
char *path = patch->new_name;
unsigned mode = patch->new_mode;
@@ -4205,25 +4350,27 @@ static void create_file(struct patch *patch)
if (!mode)
mode = S_IFREG | 0644;
- create_one_file(path, mode, buf, size);
+ create_one_file(state, path, mode, buf, size);
if (patch->conflicted_threeway)
- add_conflicted_stages_file(patch);
+ add_conflicted_stages_file(state, patch);
else
- add_index_file(path, mode, buf, size);
+ add_index_file(state, path, mode, buf, size);
}
/* phase zero is to remove, phase one is to create */
-static void write_out_one_result(struct patch *patch, int phase)
+static void write_out_one_result(struct apply_state *state,
+ struct patch *patch,
+ int phase)
{
if (patch->is_delete > 0) {
if (phase == 0)
- remove_file(patch, 1);
+ remove_file(state, patch, 1);
return;
}
if (patch->is_new > 0 || patch->is_copy) {
if (phase == 1)
- create_file(patch);
+ create_file(state, patch);
return;
}
/*
@@ -4231,12 +4378,12 @@ static void write_out_one_result(struct patch *patch, int phase)
* thing: remove the old, write the new
*/
if (phase == 0)
- remove_file(patch, patch->is_rename);
+ remove_file(state, patch, patch->is_rename);
if (phase == 1)
- create_file(patch);
+ create_file(state, patch);
}
-static int write_out_one_reject(struct patch *patch)
+static int write_out_one_reject(struct apply_state *state, struct patch *patch)
{
FILE *rej;
char namebuf[PATH_MAX];
@@ -4251,7 +4398,7 @@ static int write_out_one_reject(struct patch *patch)
}
if (!cnt) {
- if (apply_verbosely)
+ if (state->apply_verbosely)
say_patch_name(stderr,
_("Applied patch %s cleanly."), patch);
return 0;
@@ -4307,7 +4454,7 @@ static int write_out_one_reject(struct patch *patch)
return -1;
}
-static int write_out_results(struct patch *list)
+static int write_out_results(struct apply_state *state, struct patch *list)
{
int phase;
int errs = 0;
@@ -4320,9 +4467,9 @@ static int write_out_results(struct patch *list)
if (l->rejected)
errs = 1;
else {
- write_out_one_result(l, phase);
+ write_out_one_result(state, l, phase);
if (phase == 1) {
- if (write_out_one_reject(l))
+ if (write_out_one_reject(state, l))
errs = 1;
if (l->conflicted_threeway) {
string_list_append(&cpath, l->new_name);
@@ -4353,14 +4500,17 @@ static struct lock_file lock_file;
#define INACCURATE_EOF (1<<0)
#define RECOUNT (1<<1)
-static int apply_patch(int fd, const char *filename, int options)
+static int apply_patch(struct apply_state *state,
+ int fd,
+ const char *filename,
+ int options)
{
size_t offset;
struct strbuf buf = STRBUF_INIT; /* owns the patch text */
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
- patch_input_file = filename;
+ state->patch_input_file = filename;
read_patch_file(&buf, fd);
offset = 0;
while (offset < buf.len) {
@@ -4370,20 +4520,20 @@ static int apply_patch(int fd, const char *filename, int options)
patch = xcalloc(1, sizeof(*patch));
patch->inaccurate_eof = !!(options & INACCURATE_EOF);
patch->recount = !!(options & RECOUNT);
- nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
+ nr = parse_chunk(state, buf.buf + offset, buf.len - offset, patch);
if (nr < 0) {
free_patch(patch);
break;
}
- if (apply_in_reverse)
+ if (state->apply_in_reverse)
reverse_patches(patch);
- if (use_patch(patch)) {
- patch_stats(patch);
+ if (use_patch(state, patch)) {
+ patch_stats(state, patch);
*listp = patch;
listp = &patch->next;
}
else {
- if (apply_verbosely)
+ if (state->apply_verbosely)
say_patch_name(stderr, _("Skipped patch '%s'."), patch);
free_patch(patch);
skipped_patch++;
@@ -4394,45 +4544,45 @@ static int apply_patch(int fd, const char *filename, int options)
if (!list && !skipped_patch)
die(_("unrecognized input"));
- if (whitespace_error && (ws_error_action == die_on_ws_error))
- apply = 0;
+ if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
+ state->apply = 0;
- update_index = check_index && apply;
- if (update_index && newfd < 0)
- newfd = hold_locked_index(&lock_file, 1);
+ state->update_index = state->check_index && state->apply;
+ if (state->update_index && state->newfd < 0)
+ state->newfd = hold_locked_index(state->lock_file, 1);
- if (check_index) {
+ if (state->check_index) {
if (read_cache() < 0)
die(_("unable to read index file"));
}
- if ((check || apply) &&
- check_patch_list(list) < 0 &&
- !apply_with_reject)
+ if ((state->check || state->apply) &&
+ check_patch_list(state, list) < 0 &&
+ !state->apply_with_reject)
exit(1);
- if (apply && write_out_results(list)) {
- if (apply_with_reject)
+ if (state->apply && write_out_results(state, list)) {
+ if (state->apply_with_reject)
exit(1);
/* with --3way, we still need to write the index out */
return 1;
}
- if (fake_ancestor)
- build_fake_ancestor(list, fake_ancestor);
+ if (state->fake_ancestor)
+ build_fake_ancestor(list, state->fake_ancestor);
- if (diffstat)
- stat_patch_list(list);
+ if (state->diffstat)
+ stat_patch_list(state, list);
- if (numstat)
- numstat_patch_list(list);
+ if (state->numstat)
+ numstat_patch_list(state, list);
- if (summary)
+ if (state->summary)
summary_patch_list(list);
free_patch_list(list);
strbuf_release(&buf);
- string_list_clear(&fn_table, 0);
+ string_list_clear(&state->fn_table, 0);
return 0;
}
@@ -4446,220 +4596,284 @@ static void git_apply_config(void)
static int option_parse_exclude(const struct option *opt,
const char *arg, int unset)
{
- add_name_limit(arg, 1);
+ struct apply_state *state = opt->value;
+ add_name_limit(state, 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;
+ struct apply_state *state = opt->value;
+ add_name_limit(state, arg, 0);
+ state->has_include = 1;
return 0;
}
static int option_parse_p(const struct option *opt,
- const char *arg, int unset)
+ const char *arg,
+ int unset)
{
- p_value = atoi(arg);
- p_value_known = 1;
+ struct apply_state *state = opt->value;
+ state->p_value = atoi(arg);
+ state->p_value_known = 1;
return 0;
}
static int option_parse_space_change(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset)
{
+ struct apply_state *state = opt->value;
if (unset)
- ws_ignore_action = ignore_ws_none;
+ state->ws_ignore_action = ignore_ws_none;
else
- ws_ignore_action = ignore_ws_change;
+ state->ws_ignore_action = ignore_ws_change;
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);
+ struct apply_state *state = opt->value;
+ state->whitespace_option = arg;
+ parse_whitespace_option(state, arg);
return 0;
}
static int option_parse_directory(const struct option *opt,
const char *arg, int unset)
{
- strbuf_reset(&root);
- strbuf_addstr(&root, arg);
- strbuf_complete(&root, '/');
+ struct apply_state *state = opt->value;
+ strbuf_reset(&state->root);
+ strbuf_addstr(&state->root, arg);
+ strbuf_complete(&state->root, '/');
return 0;
}
-int cmd_apply(int argc, const char **argv, const char *prefix_)
+static void init_apply_state(struct apply_state *state,
+ const char *prefix,
+ struct lock_file *lock_file)
+{
+ memset(state, 0, sizeof(*state));
+ state->prefix = prefix;
+ state->prefix_length = state->prefix ? strlen(state->prefix) : 0;
+ state->lock_file = lock_file;
+ state->newfd = -1;
+ state->apply = 1;
+ state->line_termination = '\n';
+ state->p_value = 1;
+ state->p_context = UINT_MAX;
+ state->squelch_whitespace_errors = 5;
+ state->ws_error_action = warn_on_ws_error;
+ state->ws_ignore_action = ignore_ws_none;
+ state->linenr = 1;
+ string_list_init(&state->fn_table, 0);
+ string_list_init(&state->limit_by_name, 0);
+ string_list_init(&state->symlink_changes, 0);
+ strbuf_init(&state->root, 0);
+
+ git_apply_config();
+ if (apply_default_whitespace)
+ parse_whitespace_option(state, apply_default_whitespace);
+ if (apply_default_ignorewhitespace)
+ parse_ignorewhitespace_option(state, apply_default_ignorewhitespace);
+}
+
+static void clear_apply_state(struct apply_state *state)
+{
+ string_list_clear(&state->limit_by_name, 0);
+ string_list_clear(&state->symlink_changes, 0);
+ strbuf_release(&state->root);
+
+ /* &state->fn_table is cleared at the end of apply_patch() */
+}
+
+static void check_apply_state(struct apply_state *state, int force_apply)
+{
+ int is_not_gitdir = !startup_info->have_repository;
+
+ if (state->apply_with_reject && state->threeway)
+ die("--reject and --3way cannot be used together.");
+ if (state->cached && state->threeway)
+ die("--cached and --3way cannot be used together.");
+ if (state->threeway) {
+ if (is_not_gitdir)
+ die(_("--3way outside a repository"));
+ state->check_index = 1;
+ }
+ if (state->apply_with_reject)
+ state->apply = state->apply_verbosely = 1;
+ if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor))
+ state->apply = 0;
+ if (state->check_index && is_not_gitdir)
+ die(_("--index outside a repository"));
+ if (state->cached) {
+ if (is_not_gitdir)
+ die(_("--cached outside a repository"));
+ state->check_index = 1;
+ }
+ if (state->check_index)
+ state->unsafe_paths = 0;
+ if (!state->lock_file)
+ die("BUG: state->lock_file should not be NULL");
+}
+
+static int apply_all_patches(struct apply_state *state,
+ int argc,
+ const char **argv,
+ int options)
{
int i;
int errs = 0;
- int is_not_gitdir = !startup_info->have_repository;
- int force_apply = 0;
+ int read_stdin = 1;
+
+ for (i = 0; i < argc; i++) {
+ const char *arg = argv[i];
+ int fd;
+
+ if (!strcmp(arg, "-")) {
+ errs |= apply_patch(state, 0, "<stdin>", options);
+ read_stdin = 0;
+ continue;
+ } else if (0 < state->prefix_length)
+ arg = prefix_filename(state->prefix,
+ state->prefix_length,
+ arg);
+
+ fd = open(arg, O_RDONLY);
+ if (fd < 0)
+ die_errno(_("can't open patch '%s'"), arg);
+ read_stdin = 0;
+ set_default_whitespace_mode(state);
+ errs |= apply_patch(state, fd, arg, options);
+ close(fd);
+ }
+ set_default_whitespace_mode(state);
+ if (read_stdin)
+ errs |= apply_patch(state, 0, "<stdin>", options);
+
+ if (state->whitespace_error) {
+ if (state->squelch_whitespace_errors &&
+ state->squelch_whitespace_errors < state->whitespace_error) {
+ int squelched =
+ state->whitespace_error - state->squelch_whitespace_errors;
+ warning(Q_("squelched %d whitespace error",
+ "squelched %d whitespace errors",
+ squelched),
+ squelched);
+ }
+ if (state->ws_error_action == die_on_ws_error)
+ die(Q_("%d line adds whitespace errors.",
+ "%d lines add whitespace errors.",
+ state->whitespace_error),
+ state->whitespace_error);
+ if (state->applied_after_fixing_ws && state->apply)
+ warning("%d line%s applied after"
+ " fixing whitespace errors.",
+ state->applied_after_fixing_ws,
+ state->applied_after_fixing_ws == 1 ? "" : "s");
+ else if (state->whitespace_error)
+ warning(Q_("%d line adds whitespace errors.",
+ "%d lines add whitespace errors.",
+ state->whitespace_error),
+ state->whitespace_error);
+ }
+
+ if (state->update_index) {
+ if (write_locked_index(&the_index, state->lock_file, COMMIT_LOCK))
+ die(_("Unable to write new index file"));
+ state->newfd = -1;
+ }
+
+ return !!errs;
+}
- const char *whitespace_option = NULL;
+int cmd_apply(int argc, const char **argv, const char *prefix)
+{
+ int force_apply = 0;
+ int options = 0;
+ int ret;
+ struct apply_state state;
struct option builtin_apply_options[] = {
- { OPTION_CALLBACK, 0, "exclude", NULL, N_("path"),
+ { OPTION_CALLBACK, 0, "exclude", &state, N_("path"),
N_("don't apply changes matching the given path"),
0, option_parse_exclude },
- { OPTION_CALLBACK, 0, "include", NULL, N_("path"),
+ { OPTION_CALLBACK, 0, "include", &state, N_("path"),
N_("apply changes matching the given path"),
0, option_parse_include },
- { OPTION_CALLBACK, 'p', NULL, NULL, N_("num"),
+ { OPTION_CALLBACK, 'p', NULL, &state, N_("num"),
N_("remove <num> leading slashes from traditional diff paths"),
0, option_parse_p },
- OPT_BOOL(0, "no-add", &no_add,
+ OPT_BOOL(0, "no-add", &state.no_add,
N_("ignore additions made by the patch")),
- OPT_BOOL(0, "stat", &diffstat,
+ OPT_BOOL(0, "stat", &state.diffstat,
N_("instead of applying the patch, output diffstat for the input")),
OPT_NOOP_NOARG(0, "allow-binary-replacement"),
OPT_NOOP_NOARG(0, "binary"),
- OPT_BOOL(0, "numstat", &numstat,
+ OPT_BOOL(0, "numstat", &state.numstat,
N_("show number of added and deleted lines in decimal notation")),
- OPT_BOOL(0, "summary", &summary,
+ OPT_BOOL(0, "summary", &state.summary,
N_("instead of applying the patch, output a summary for the input")),
- OPT_BOOL(0, "check", &check,
+ OPT_BOOL(0, "check", &state.check,
N_("instead of applying the patch, see if the patch is applicable")),
- OPT_BOOL(0, "index", &check_index,
+ OPT_BOOL(0, "index", &state.check_index,
N_("make sure the patch is applicable to the current index")),
- OPT_BOOL(0, "cached", &cached,
+ OPT_BOOL(0, "cached", &state.cached,
N_("apply a patch without touching the working tree")),
- OPT_BOOL(0, "unsafe-paths", &unsafe_paths,
+ OPT_BOOL(0, "unsafe-paths", &state.unsafe_paths,
N_("accept a patch that touches outside the working area")),
OPT_BOOL(0, "apply", &force_apply,
N_("also apply the patch (use with --stat/--summary/--check)")),
- OPT_BOOL('3', "3way", &threeway,
+ OPT_BOOL('3', "3way", &state.threeway,
N_( "attempt three-way merge if a patch does not apply")),
- OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
+ OPT_FILENAME(0, "build-fake-ancestor", &state.fake_ancestor,
N_("build a temporary index based on embedded index information")),
/* Think twice before adding "--nul" synonym to this */
- OPT_SET_INT('z', NULL, &line_termination,
+ OPT_SET_INT('z', NULL, &state.line_termination,
N_("paths are separated with NUL character"), '\0'),
- OPT_INTEGER('C', NULL, &p_context,
+ OPT_INTEGER('C', NULL, &state.p_context,
N_("ensure at least <n> lines of context match")),
- { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"),
+ { OPTION_CALLBACK, 0, "whitespace", &state, N_("action"),
N_("detect new or modified lines that have whitespace errors"),
0, option_parse_whitespace },
- { OPTION_CALLBACK, 0, "ignore-space-change", NULL, NULL,
+ { OPTION_CALLBACK, 0, "ignore-space-change", &state, NULL,
N_("ignore changes in whitespace when finding context"),
PARSE_OPT_NOARG, option_parse_space_change },
- { OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
+ { OPTION_CALLBACK, 0, "ignore-whitespace", &state, NULL,
N_("ignore changes in whitespace when finding context"),
PARSE_OPT_NOARG, option_parse_space_change },
- OPT_BOOL('R', "reverse", &apply_in_reverse,
+ OPT_BOOL('R', "reverse", &state.apply_in_reverse,
N_("apply the patch in reverse")),
- OPT_BOOL(0, "unidiff-zero", &unidiff_zero,
+ OPT_BOOL(0, "unidiff-zero", &state.unidiff_zero,
N_("don't expect at least one line of context")),
- OPT_BOOL(0, "reject", &apply_with_reject,
+ OPT_BOOL(0, "reject", &state.apply_with_reject,
N_("leave the rejected hunks in corresponding *.rej files")),
- OPT_BOOL(0, "allow-overlap", &allow_overlap,
+ OPT_BOOL(0, "allow-overlap", &state.allow_overlap,
N_("allow overlapping hunks")),
- OPT__VERBOSE(&apply_verbosely, N_("be verbose")),
+ OPT__VERBOSE(&state.apply_verbosely, N_("be verbose")),
OPT_BIT(0, "inaccurate-eof", &options,
N_("tolerate incorrectly detected missing new-line at the end of file"),
INACCURATE_EOF),
OPT_BIT(0, "recount", &options,
N_("do not trust the line counts in the hunk headers"),
RECOUNT),
- { OPTION_CALLBACK, 0, "directory", NULL, N_("root"),
+ { OPTION_CALLBACK, 0, "directory", &state, N_("root"),
N_("prepend <root> to all filenames"),
0, option_parse_directory },
OPT_END()
};
- prefix = prefix_;
- prefix_length = prefix ? strlen(prefix) : 0;
- git_apply_config();
- if (apply_default_whitespace)
- parse_whitespace_option(apply_default_whitespace);
- if (apply_default_ignorewhitespace)
- parse_ignorewhitespace_option(apply_default_ignorewhitespace);
+ init_apply_state(&state, prefix, &lock_file);
- argc = parse_options(argc, argv, prefix, builtin_apply_options,
+ argc = parse_options(argc, argv, state.prefix, builtin_apply_options,
apply_usage, 0);
- if (apply_with_reject && threeway)
- die("--reject and --3way cannot be used together.");
- if (cached && threeway)
- die("--cached and --3way cannot be used together.");
- if (threeway) {
- if (is_not_gitdir)
- die(_("--3way outside a repository"));
- check_index = 1;
- }
- 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;
- }
- if (check_index)
- unsafe_paths = 0;
+ check_apply_state(&state, force_apply);
- for (i = 0; i < argc; i++) {
- const char *arg = argv[i];
- int fd;
+ ret = apply_all_patches(&state, argc, argv, options);
- if (!strcmp(arg, "-")) {
- errs |= apply_patch(0, "<stdin>", options);
- read_stdin = 0;
- continue;
- } else if (0 < prefix_length)
- arg = prefix_filename(prefix, prefix_length, arg);
+ clear_apply_state(&state);
- fd = open(arg, O_RDONLY);
- if (fd < 0)
- die_errno(_("can't open patch '%s'"), arg);
- read_stdin = 0;
- set_default_whitespace_mode(whitespace_option);
- errs |= apply_patch(fd, arg, options);
- close(fd);
- }
- set_default_whitespace_mode(whitespace_option);
- if (read_stdin)
- errs |= apply_patch(0, "<stdin>", options);
- if (whitespace_error) {
- if (squelch_whitespace_errors &&
- squelch_whitespace_errors < whitespace_error) {
- int squelched =
- whitespace_error - squelch_whitespace_errors;
- warning(Q_("squelched %d whitespace error",
- "squelched %d whitespace errors",
- squelched),
- squelched);
- }
- if (ws_error_action == die_on_ws_error)
- die(Q_("%d line adds whitespace errors.",
- "%d lines add whitespace errors.",
- whitespace_error),
- whitespace_error);
- if (applied_after_fixing_ws && apply)
- warning("%d line%s applied after"
- " fixing whitespace errors.",
- applied_after_fixing_ws,
- applied_after_fixing_ws == 1 ? "" : "s");
- else if (whitespace_error)
- warning(Q_("%d line adds whitespace errors.",
- "%d lines add whitespace errors.",
- whitespace_error),
- whitespace_error);
- }
-
- if (update_index) {
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
- die(_("Unable to write new index file"));
- }
-
- return !!errs;
+ return ret;
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 21f42b0..1e214bd 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -56,7 +56,7 @@ static int show_progress;
static struct date_mode blame_date_mode = { DATE_ISO8601 };
static size_t blame_date_width;
-static struct string_list mailmap;
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
#ifndef DEBUG
#define DEBUG 0
@@ -609,7 +609,7 @@ static struct origin *find_origin(struct scoreboard *sb,
}
}
diff_flush(&diff_opts);
- free_pathspec(&diff_opts.pathspec);
+ clear_pathspec(&diff_opts.pathspec);
return porigin;
}
@@ -651,7 +651,7 @@ static struct origin *find_rename(struct scoreboard *sb,
}
}
diff_flush(&diff_opts);
- free_pathspec(&diff_opts.pathspec);
+ clear_pathspec(&diff_opts.pathspec);
return porigin;
}
@@ -1343,7 +1343,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
} while (unblamed);
target->suspects = reverse_blame(leftover, NULL);
diff_flush(&diff_opts);
- free_pathspec(&diff_opts.pathspec);
+ clear_pathspec(&diff_opts.pathspec);
}
/*
@@ -2425,8 +2425,7 @@ static struct commit *find_single_final(struct rev_info *revs,
struct object *obj = revs->pending.objects[i].item;
if (obj->flags & UNINTERESTING)
continue;
- while (obj->type == OBJ_TAG)
- obj = deref_tag(obj, NULL, 0);
+ obj = deref_tag(obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (found)
@@ -2461,8 +2460,7 @@ static char *prepare_initial(struct scoreboard *sb)
struct object *obj = revs->pending.objects[i].item;
if (!(obj->flags & UNINTERESTING))
continue;
- while (obj->type == OBJ_TAG)
- obj = deref_tag(obj, NULL, 0);
+ obj = deref_tag(obj, NULL, 0);
if (obj->type != OBJ_COMMIT)
die("Non commit %s?", revs->pending.objects[i].name);
if (sb->final)
@@ -2522,12 +2520,12 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
enum object_type type;
struct commit *final_commit = NULL;
- static struct string_list range_list;
- static int output_option = 0, opt = 0;
- static int show_stats = 0;
- static const char *revs_file = NULL;
- static const char *contents_from = NULL;
- static const struct option options[] = {
+ struct string_list range_list = STRING_LIST_INIT_NODUP;
+ int output_option = 0, opt = 0;
+ int show_stats = 0;
+ const char *revs_file = NULL;
+ const char *contents_from = NULL;
+ const struct option options[] = {
OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 54db118..618103f 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -154,6 +154,13 @@ struct expand_data {
* elements above, so you can retrieve the response from there.
*/
struct object_info info;
+
+ /*
+ * This flag will be true if the requested batch format and options
+ * don't require us to call sha1_object_info, which can then be
+ * optimized out.
+ */
+ unsigned skip_object_info : 1;
};
static int is_atom(const char *atom, const char *s, int slen)
@@ -258,7 +265,8 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
{
struct strbuf buf = STRBUF_INIT;
- if (sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
+ if (!data->skip_object_info &&
+ sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
printf("%s missing\n", obj_name ? obj_name : sha1_to_hex(data->sha1));
fflush(stdout);
return;
@@ -369,6 +377,13 @@ static int batch_objects(struct batch_options *opt)
strbuf_expand(&buf, opt->format, expand_format, &data);
data.mark_query = 0;
+ if (opt->all_objects) {
+ struct object_info empty;
+ memset(&empty, 0, sizeof(empty));
+ if (!memcmp(&data.info, &empty, sizeof(empty)))
+ data.skip_object_info = 1;
+ }
+
/*
* If we are printing out the object, then always fill in the type,
* since we will want to decide whether or not to stream.
@@ -489,6 +504,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
git_config(git_cat_file_config, NULL);
+ batch.buffer_output = -1;
argc = parse_options(argc, argv, prefix, options, cat_file_usage, 0);
if (opt) {
@@ -512,6 +528,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
usage_with_options(cat_file_usage, options);
}
+ if (batch.buffer_output < 0)
+ batch.buffer_output = batch.all_objects;
+
if (batch.enabled)
return batch_objects(&batch);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 05c7b71..27c1a05 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -548,7 +548,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
* entries in the index.
*/
- add_files_to_cache(NULL, NULL, 0);
+ add_files_to_cache(NULL, NULL, 0, 0);
/*
* NEEDSWORK: carrying over local changes
* when branches have different end-of-line
diff --git a/builtin/clone.c b/builtin/clone.c
index 5f867e6..31ea247 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -40,7 +40,7 @@ static const char * const builtin_clone_usage[] = {
static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
-static int option_shallow_submodules = -1;
+static int option_shallow_submodules;
static char *option_template, *option_depth;
static char *option_origin = NULL;
static char *option_branch = NULL;
@@ -49,8 +49,8 @@ static char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
static enum transport_family family;
-static struct string_list option_config;
-static struct string_list option_reference;
+static struct string_list option_config = STRING_LIST_INIT_NODUP;
+static struct string_list option_reference = STRING_LIST_INIT_NODUP;
static int option_dissociate;
static int max_jobs = -1;
@@ -738,8 +738,7 @@ static int checkout(void)
struct argv_array args = ARGV_ARRAY_INIT;
argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL);
- if (option_shallow_submodules == 1
- || (option_shallow_submodules == -1 && option_depth))
+ if (option_shallow_submodules == 1)
argv_array_push(&args, "--depth=1");
if (max_jobs != -1)
diff --git a/builtin/commit.c b/builtin/commit.c
index 443ff91..1f6dbcd 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -92,8 +92,9 @@ N_("If you wish to skip this commit, use:\n"
"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
"the remaining commits.\n");
+static GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
+
static const char *use_message_buffer;
-static const char commit_editmsg[] = "COMMIT_EDITMSG";
static struct lock_file index_lock; /* real index */
static struct lock_file false_lock; /* used only for partial commits */
static enum {
@@ -386,7 +387,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
*/
if (all || (also && pathspec.nr)) {
hold_locked_index(&index_lock, 1);
- add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
+ add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0);
refresh_cache_or_die(refresh_flags);
update_main_cache_tree(WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
@@ -714,7 +715,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
char *buffer;
buffer = strstr(use_message_buffer, "\n\n");
if (buffer)
- strbuf_addstr(&sb, buffer + 2);
+ strbuf_addstr(&sb, skip_blank_lines(buffer + 2));
hook_arg1 = "commit";
hook_arg2 = use_message;
} else if (fixup_message) {
@@ -772,9 +773,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
hook_arg2 = "";
}
- s->fp = fopen_for_writing(git_path(commit_editmsg));
+ s->fp = fopen_for_writing(git_path_commit_editmsg());
if (s->fp == NULL)
- die_errno(_("could not open '%s'"), git_path(commit_editmsg));
+ die_errno(_("could not open '%s'"), git_path_commit_editmsg());
/* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
old_display_comment_prefix = s->display_comment_prefix;
@@ -951,7 +952,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
if (run_commit_hook(use_editor, index_file, "prepare-commit-msg",
- git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
+ git_path_commit_editmsg(), hook_arg1, hook_arg2, NULL))
return 0;
if (use_editor) {
@@ -959,7 +960,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
const char *env[2] = { NULL };
env[0] = index;
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
- if (launch_editor(git_path(commit_editmsg), NULL, env)) {
+ if (launch_editor(git_path_commit_editmsg(), NULL, env)) {
fprintf(stderr,
_("Please supply the message using either -m or -F option.\n"));
exit(1);
@@ -967,7 +968,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
if (!no_verify &&
- run_commit_hook(use_editor, index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
+ run_commit_hook(use_editor, index_file, "commit-msg", git_path_commit_editmsg(), NULL)) {
return 0;
}
@@ -1738,7 +1739,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
/* Finally, get the commit message */
strbuf_reset(&sb);
- if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
+ if (strbuf_read_file(&sb, git_path_commit_editmsg(), 0) < 0) {
int saved_errno = errno;
rollback_index_files();
die(_("could not read commit message: %s"), strerror(saved_errno));
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 1582ca7..f896aa1 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1005,7 +1005,7 @@ static int get_remote_group(const char *key, const char *value, void *priv)
size_t wordlen = strcspn(value, " \t\n");
if (wordlen >= 1)
- string_list_append(g->list,
+ string_list_append_nodup(g->list,
xstrndup(value, wordlen));
value += wordlen + (value[wordlen] != '\0');
}
@@ -1143,7 +1143,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
int i;
- struct string_list list = STRING_LIST_INIT_NODUP;
+ struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote;
int result = 0;
struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
@@ -1226,8 +1226,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
argv_array_clear(&options);
}
- /* All names were strdup()ed or strndup()ed */
- list.strdup_strings = 1;
string_list_clear(&list, 0);
close_all_packs();
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index b99ae4b..175f147 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -20,7 +20,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
{
int in_place = 0;
int trim_empty = 0;
- struct string_list trailers = STRING_LIST_INIT_DUP;
+ struct string_list trailers = STRING_LIST_INIT_NODUP;
struct option options[] = {
OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
diff --git a/builtin/log.c b/builtin/log.c
index 099f4f7..0b6f739 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -33,6 +33,7 @@ static const char *default_date_mode = NULL;
static int default_abbrev_commit;
static int default_show_root = 1;
static int default_follow;
+static int default_show_signature;
static int decoration_style;
static int decoration_given;
static int use_mailmap_config;
@@ -119,6 +120,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
+ rev->show_signature = default_show_signature;
DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
if (default_date_mode)
@@ -409,6 +411,10 @@ static int git_log_config(const char *var, const char *value, void *cb)
use_mailmap_config = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "log.showsignature")) {
+ default_show_signature = git_config_bool(var, value);
+ return 0;
+ }
if (grep_config(var, value, cb) < 0)
return -1;
@@ -674,9 +680,9 @@ static int auto_number = 1;
static char *default_attach = NULL;
-static struct string_list extra_hdr;
-static struct string_list extra_to;
-static struct string_list extra_cc;
+static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
+static struct string_list extra_to = STRING_LIST_INIT_NODUP;
+static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
static void add_header(const char *value)
{
@@ -953,7 +959,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct pretty_print_context pp = {0};
struct commit *head = list[0];
- if (rev->commit_format != CMIT_FMT_EMAIL)
+ if (!cmit_fmt_is_mail(rev->commit_format))
die(_("Cover letter needs email format"));
committer = git_committer_info(0);
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 4859ede..3068168 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -45,6 +45,19 @@ static int is_from_line(const char *line, int len)
static struct strbuf buf = STRBUF_INIT;
static int keep_cr;
+static int mboxrd;
+
+static int is_gtfrom(const struct strbuf *buf)
+{
+ size_t min = strlen(">From ");
+ size_t ngt;
+
+ if (buf->len < min)
+ return 0;
+
+ ngt = strspn(buf->buf, ">");
+ return ngt && starts_with(buf->buf + ngt, "From ");
+}
/* Called with the first line (potentially partial)
* already in buf[] -- normally that should begin with
@@ -77,6 +90,9 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
strbuf_addch(&buf, '\n');
}
+ if (mboxrd && is_gtfrom(&buf))
+ strbuf_remove(&buf, 0, 1);
+
if (fwrite(buf.buf, 1, buf.len, output) != buf.len)
die_errno("cannot write output");
@@ -271,6 +287,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
keep_cr = 1;
} else if ( arg[1] == 'o' && arg[2] ) {
dir = arg+2;
+ } else if (!strcmp(arg, "--mboxrd")) {
+ mboxrd = 1;
} else if ( arg[1] == '-' && !arg[2] ) {
argp++; /* -- marks end of options */
break;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 8f5e358..a2f8cfd 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -44,6 +44,7 @@ static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
static int keep_unreachable, unpack_unreachable, include_tag;
static unsigned long unpack_unreachable_expiration;
+static int pack_loose_unreachable;
static int local;
static int incremental;
static int ignore_packed_keep;
@@ -2378,6 +2379,32 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
free(in_pack.array);
}
+static int add_loose_object(const unsigned char *sha1, const char *path,
+ void *data)
+{
+ enum object_type type = sha1_object_info(sha1, NULL);
+
+ if (type < 0) {
+ warning("loose object at %s could not be examined", path);
+ return 0;
+ }
+
+ add_object_entry(sha1, type, "", 0);
+ return 0;
+}
+
+/*
+ * We actually don't even have to worry about reachability here.
+ * add_object_entry will weed out duplicates, so we just add every
+ * loose object we find.
+ */
+static void add_unreachable_loose_objects(void)
+{
+ for_each_loose_file_in_objdir(get_object_directory(),
+ add_loose_object,
+ NULL, NULL, NULL);
+}
+
static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
{
static struct packed_git *last_found = (void *)1;
@@ -2547,6 +2574,8 @@ static void get_object_list(int ac, const char **av)
if (keep_unreachable)
add_objects_in_unpacked_packs(&revs);
+ if (pack_loose_unreachable)
+ add_unreachable_loose_objects();
if (unpack_unreachable)
loosen_unused_packed_objects(&revs);
@@ -2647,6 +2676,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("include tag objects that refer to objects to be packed")),
OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
N_("keep unreachable objects")),
+ OPT_BOOL(0, "pack-loose-unreachable", &pack_loose_unreachable,
+ N_("pack loose unreachable objects")),
{ OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
N_("unpack unreachable objects newer than <time>"),
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 366ce5a..a84d000 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -81,16 +81,13 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) {
char *line = line_buf->buf;
- char *p = line;
+ const char *p = line;
int len;
- if (!memcmp(line, "diff-tree ", 10))
- p += 10;
- else if (!memcmp(line, "commit ", 7))
- p += 7;
- else if (!memcmp(line, "From ", 5))
- p += 5;
- else if (!memcmp(line, "\\ ", 2) && 12 < strlen(line))
+ if (!skip_prefix(line, "diff-tree ", &p) &&
+ !skip_prefix(line, "commit ", &p) &&
+ !skip_prefix(line, "From ", &p) &&
+ starts_with(line, "\\ ") && 12 < strlen(line))
continue;
if (!get_oid_hex(p, next_oid)) {
@@ -99,14 +96,14 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
}
/* Ignore commit comments */
- if (!patchlen && memcmp(line, "diff ", 5))
+ if (!patchlen && !starts_with(line, "diff "))
continue;
/* Parsing diff header? */
if (before == -1) {
- if (!memcmp(line, "index ", 6))
+ if (starts_with(line, "index "))
continue;
- else if (!memcmp(line, "--- ", 4))
+ else if (starts_with(line, "--- "))
before = after = 1;
else if (!isalpha(line[0]))
break;
@@ -114,14 +111,14 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
/* Looking for a valid hunk header? */
if (before == 0 && after == 0) {
- if (!memcmp(line, "@@ -", 4)) {
+ if (starts_with(line, "@@ -")) {
/* Parse next hunk, but ignore line numbers. */
scan_hunk_header(line, &before, &after);
continue;
}
/* Split at the end of the patch. */
- if (memcmp(line, "diff ", 5))
+ if (!starts_with(line, "diff "))
break;
/* Else we're parsing another header. */
diff --git a/builtin/pull.c b/builtin/pull.c
index a980dcf..398aae1 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -815,6 +815,9 @@ static int run_rebase(const unsigned char *curr_head,
argv_array_push(&args, "--no-autostash");
else if (opt_autostash == 1)
argv_array_push(&args, "--autostash");
+ if (opt_verify_signatures &&
+ !strcmp(opt_verify_signatures, "--verify-signatures"))
+ warning(_("ignoring --verify-signatures for rebase"));
argv_array_push(&args, "--onto");
argv_array_push(&args, sha1_to_hex(merge_head));
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index a744437..15c323a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1775,9 +1775,20 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
const char *argv_gc_auto[] = {
"gc", "--auto", "--quiet", NULL,
};
- int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
+ struct child_process proc = CHILD_PROCESS_INIT;
+
+ proc.no_stdin = 1;
+ proc.stdout_to_stderr = 1;
+ proc.err = use_sideband ? -1 : 0;
+ proc.git_cmd = 1;
+ proc.argv = argv_gc_auto;
+
close_all_packs();
- run_command_v_opt(argv_gc_auto, opt);
+ if (!start_command(&proc)) {
+ if (use_sideband)
+ copy_to_sideband(proc.err, -1, NULL);
+ finish_command(&proc);
+ }
}
if (auto_update_server_info)
update_server_info(0);
diff --git a/builtin/remote.c b/builtin/remote.c
index 7f0f78b..a4d9c1a 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -247,7 +247,7 @@ struct branch_info {
enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
};
-static struct string_list branch_list;
+static struct string_list branch_list = STRING_LIST_INIT_NODUP;
static const char *abbrev_ref(const char *name, const char *prefix)
{
diff --git a/builtin/repack.c b/builtin/repack.c
index 0108819..80dd06b 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -146,6 +146,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
int pack_everything = 0;
int delete_redundant = 0;
const char *unpack_unreachable = NULL;
+ int keep_unreachable = 0;
const char *window = NULL, *window_memory = NULL;
const char *depth = NULL;
const char *max_pack_size = NULL;
@@ -175,6 +176,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("write bitmap index")),
OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
N_("with -A, do not loosen objects older than this")),
+ OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
+ N_("with -a, repack unreachable objects")),
OPT_STRING(0, "window", &window, N_("n"),
N_("size of the window used for delta compression")),
OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
@@ -196,6 +199,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant && repository_format_precious_objects)
die(_("cannot delete packs in a precious-objects repo"));
+ if (keep_unreachable &&
+ (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
+ die(_("--keep-unreachable and -A are incompatible"));
+
if (pack_kept_objects < 0)
pack_kept_objects = write_bitmaps;
@@ -239,6 +246,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
} else if (pack_everything & LOOSEN_UNREACHABLE) {
argv_array_push(&cmd.args,
"--unpack-unreachable");
+ } else if (keep_unreachable) {
+ argv_array_push(&cmd.args, "--keep-unreachable");
+ argv_array_push(&cmd.args, "--pack-loose-unreachable");
} else {
argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 092c3a5..5c6206b 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -103,7 +103,7 @@ static void print_new_head_line(struct commit *commit)
if (body) {
const char *eol;
size_t len;
- body += 2;
+ body = skip_blank_lines(body + 2);
eol = strchr(body, '\n');
len = eol ? eol - body : strlen(body);
printf(" %.*s\n", (int) len, body);
@@ -158,7 +158,7 @@ static int read_from_tree(const struct pathspec *pathspec,
return 1;
diffcore_std(&opt);
diff_flush(&opt);
- free_pathspec(&opt.pathspec);
+ clear_pathspec(&opt.pathspec);
return 0;
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 275da0d..b82bcc3 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -358,12 +358,16 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (use_bitmap_index && !revs.prune) {
if (revs.count && !revs.left_right && !revs.cherry_mark) {
uint32_t commit_count;
+ int max_count = revs.max_count;
if (!prepare_bitmap_walk(&revs)) {
count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
+ if (max_count >= 0 && max_count < commit_count)
+ commit_count = max_count;
printf("%d\n", commit_count);
return 0;
}
- } else if (revs.tag_objects && revs.tree_objects && revs.blob_objects) {
+ } else if (revs.max_count < 0 &&
+ revs.tag_objects && revs.tree_objects && revs.blob_objects) {
if (!prepare_bitmap_walk(&revs)) {
traverse_bitmap_commit_list(&show_object_fast);
return 0;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index bfc082e..f83984e 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -233,11 +233,11 @@ void shortlog_init(struct shortlog *log)
int cmd_shortlog(int argc, const char **argv, const char *prefix)
{
- static struct shortlog log;
- static struct rev_info rev;
+ struct shortlog log = { STRING_LIST_INIT_NODUP };
+ struct rev_info rev;
int nongit = !startup_info->have_repository;
- static const struct option options[] = {
+ const struct option options[] = {
OPT_BOOL('n', "numbered", &log.sort_by_number,
N_("sort output according to the number of commits per author")),
OPT_BOOL('s', "summary", &log.summary,
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 8da263f..b22352b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -287,10 +287,8 @@ static int module_list(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_list_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) {
- printf("#unmatched\n");
+ if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
return 1;
- }
for (i = 0; i < list.nr; i++) {
const struct cache_entry *ce = list.entries[i];
@@ -581,6 +579,7 @@ struct submodule_update_clone {
/* configuration parameters which are passed on to the children */
int quiet;
+ int recommend_shallow;
const char *reference;
const char *depth;
const char *recursive_prefix;
@@ -591,10 +590,14 @@ struct submodule_update_clone {
/* If we want to stop as fast as possible and return an error */
unsigned quickstop : 1;
+
+ /* failed clones to be retried again */
+ const struct cache_entry **failed_clones;
+ int failed_clones_nr, failed_clones_alloc;
};
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
- SUBMODULE_UPDATE_STRATEGY_INIT, 0, NULL, NULL, NULL, NULL, \
- STRING_LIST_INIT_DUP, 0}
+ SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, NULL, NULL, NULL, NULL, \
+ STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@@ -698,6 +701,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
argv_array_push(&child->args, "--quiet");
if (suc->prefix)
argv_array_pushl(&child->args, "--prefix", suc->prefix, NULL);
+ if (suc->recommend_shallow && sub->recommend_shallow == 1)
+ argv_array_push(&child->args, "--depth=1");
argv_array_pushl(&child->args, "--path", sub->path, NULL);
argv_array_pushl(&child->args, "--name", sub->name, NULL);
argv_array_pushl(&child->args, "--url", url, NULL);
@@ -717,23 +722,47 @@ cleanup:
static int update_clone_get_next_task(struct child_process *child,
struct strbuf *err,
void *suc_cb,
- void **void_task_cb)
+ void **idx_task_cb)
{
struct submodule_update_clone *suc = suc_cb;
+ const struct cache_entry *ce;
+ int index;
for (; suc->current < suc->list.nr; suc->current++) {
- const struct cache_entry *ce = suc->list.entries[suc->current];
+ ce = suc->list.entries[suc->current];
if (prepare_to_clone_next_submodule(ce, child, suc, err)) {
+ int *p = xmalloc(sizeof(*p));
+ *p = suc->current;
+ *idx_task_cb = p;
suc->current++;
return 1;
}
}
+
+ /*
+ * The loop above tried cloning each submodule once, now try the
+ * stragglers again, which we can imagine as an extension of the
+ * entry list.
+ */
+ index = suc->current - suc->list.nr;
+ if (index < suc->failed_clones_nr) {
+ int *p;
+ ce = suc->failed_clones[index];
+ if (!prepare_to_clone_next_submodule(ce, child, suc, err))
+ die("BUG: ce was a submodule before?");
+ p = xmalloc(sizeof(*p));
+ *p = suc->current;
+ *idx_task_cb = p;
+ suc->current ++;
+ return 1;
+ }
+
return 0;
}
static int update_clone_start_failure(struct strbuf *err,
void *suc_cb,
- void *void_task_cb)
+ void *idx_task_cb)
{
struct submodule_update_clone *suc = suc_cb;
suc->quickstop = 1;
@@ -743,15 +772,39 @@ static int update_clone_start_failure(struct strbuf *err,
static int update_clone_task_finished(int result,
struct strbuf *err,
void *suc_cb,
- void *void_task_cb)
+ void *idx_task_cb)
{
+ const struct cache_entry *ce;
struct submodule_update_clone *suc = suc_cb;
+ int *idxP = *(int**)idx_task_cb;
+ int idx = *idxP;
+ free(idxP);
+
if (!result)
return 0;
- suc->quickstop = 1;
- return 1;
+ if (idx < suc->list.nr) {
+ ce = suc->list.entries[idx];
+ strbuf_addf(err, _("Failed to clone '%s'. Retry scheduled"),
+ ce->name);
+ strbuf_addch(err, '\n');
+ ALLOC_GROW(suc->failed_clones,
+ suc->failed_clones_nr + 1,
+ suc->failed_clones_alloc);
+ suc->failed_clones[suc->failed_clones_nr++] = ce;
+ return 0;
+ } else {
+ idx = suc->current - suc->list.nr;
+ ce = suc->failed_clones[idx];
+ strbuf_addf(err, _("Failed to clone '%s' a second time, aborting"),
+ ce->name);
+ strbuf_addch(err, '\n');
+ suc->quickstop = 1;
+ return 1;
+ }
+
+ return 0;
}
static int update_clone(int argc, const char **argv, const char *prefix)
@@ -780,6 +833,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
"specified number of revisions")),
OPT_INTEGER('j', "jobs", &max_jobs,
N_("parallel jobs")),
+ OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
+ N_("whether the initial clone should follow the shallow recommendation")),
OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
OPT_END()
};
@@ -833,6 +888,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)
return 0;
}
+static int resolve_relative_path(int argc, const char **argv, const char *prefix)
+{
+ struct strbuf sb = STRBUF_INIT;
+ if (argc != 3)
+ die("submodule--helper relative_path takes exactly 2 arguments, got %d", argc);
+
+ printf("%s", relative_path(argv[1], argv[2], &sb));
+ strbuf_release(&sb);
+ return 0;
+}
+
struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, const char *);
@@ -843,6 +909,7 @@ static struct cmd_struct commands[] = {
{"name", module_name},
{"clone", module_clone},
{"update-clone", update_clone},
+ {"relative-path", resolve_relative_path},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
{"init", module_init}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index b8b8522..6cdfd5f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -759,7 +759,7 @@ static int do_reupdate(int ac, const char **av,
if (save_nr != active_nr)
goto redo;
}
- free_pathspec(&pathspec);
+ clear_pathspec(&pathspec);
return 0;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 96a2834..e866844 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -13,8 +13,8 @@
static const char * const worktree_usage[] = {
N_("git worktree add [<options>] <path> [<branch>]"),
- N_("git worktree prune [<options>]"),
N_("git worktree list [<options>]"),
+ N_("git worktree prune [<options>]"),
NULL
};
@@ -95,7 +95,7 @@ static void prune_worktrees(void)
if (!dir)
return;
while ((d = readdir(dir)) != NULL) {
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ if (is_dot_or_dotdot(d->d_name))
continue;
strbuf_reset(&reason);
if (!prune_worktree(d->d_name, &reason))
@@ -262,7 +262,7 @@ static int add_worktree(const char *path, const char *refname,
*/
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
- write_file(sb.buf, "0000000000000000000000000000000000000000");
+ write_file(sb.buf, sha1_to_hex(null_sha1));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -337,9 +337,12 @@ static int add(int ac, const char **av, const char *prefix)
if (ac < 1 || ac > 2)
usage_with_options(worktree_usage, options);
- path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
+ path = prefix_filename(prefix, strlen(prefix), av[0]);
branch = ac < 2 ? "HEAD" : av[1];
+ if (!strcmp(branch, "-"))
+ branch = "@{-1}";
+
opts.force_new_branch = !!new_branch_force;
if (opts.force_new_branch) {
struct strbuf symref = STRBUF_INIT;
@@ -467,6 +470,8 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
if (ac < 2)
usage_with_options(worktree_usage, options);
+ if (!prefix)
+ prefix = "";
if (!strcmp(av[1], "add"))
return add(ac - 1, av + 1, prefix);
if (!strcmp(av[1], "prune"))