--- /dev/null
+Git v1.8.0.1 Release Notes
+==========================
+
+Fixes since v1.8.0
+------------------
+
+ * The configuration parser had an unnecessary hardcoded limit on
+ variable names that was not checked consistently.
+
+ * The "say" function in the test scaffolding incorrectly allowed
+ "echo" to interpret "\a" as if it were a C-string asking for a
+ BEL output.
+
+ * "git mergetool" feeds /dev/null as a common ancestor when dealing
+ with an add/add conflict, but p4merge backend cannot handle
+ it. Work it around by passing a temporary empty file.
+
+ * "git log -F -E --grep='<ere>'" failed to use the given <ere>
+ pattern as extended regular expression, and instead looked for the
+ string literally.
+
+ * "git grep -e pattern <tree>" asked the attribute system to read
+ "<tree>:.gitattributes" file in the working tree, which was
+ nonsense.
+
+ * A symbolic ref refs/heads/SYM was not correctly removed with "git
+ branch -d SYM"; the command removed the ref pointed by SYM
+ instead.
+
+ * Earlier we fixed documentation to hyphenate "remote-tracking branch"
+ to clarify that these are not a remote entity, but unhyphenated
+ spelling snuck in to a few places since then.
+
+ * "git pull --rebase" run while the HEAD is detached tried to find
+ the upstream branch of the detached HEAD (which by definition
+ does not exist) and emitted unnecessary error messages.
+
+ * The refs/replace hierarchy was not mentioned in the
+ repository-layout docs.
+
+ * Sometimes curl_multi_timeout() function suggested a wrong timeout
+ value when there is no file descriptors to wait on and the http
+ transport ended up sleeping for minutes in select(2) system call.
+ A workaround has been added for this.
+
+ * Various rfc2047 quoting issues around a non-ASCII name on the
+ From: line in the output from format-patch have been corrected.
+
+ * "git diff -G<pattern>" did not honor textconv filter when looking
+ for changes.
+
+Also contains other minor fixes and documentation updates.
`--no-single-branch` is given to fetch the histories near the
tips of all branches.
Further fetches into the resulting repository will only update the
- remote tracking branch for the branch this option was used for the
+ remote-tracking branch for the branch this option was used for the
initial cloning. If the HEAD at the remote did not point at any
- branch when `--single-branch` clone was made, no remote tracking
+ branch when `--single-branch` clone was made, no remote-tracking
branch is created.
--recursive::
commit log message unmodified. This option lets you
further edit the message taken from these sources.
+--no-edit::
+ Use the selected commit message without launching an editor.
+ For example, `git commit --amend --no-edit` amends a commit
+ without changing its commit message.
+
--amend::
Used to amend the tip of the current branch. Prepare the tree
object you would want to replace the latest commit as usual
current tip -- if it was a merge, it will have the parents of
the current tip as parents -- so the current top commit is
discarded.
-
---no-post-rewrite::
- Bypass the post-rewrite hook.
-
+
--
It is a rough equivalent for:
amend a commit that has already been published. (See the "RECOVERING
FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
+--no-post-rewrite::
+ Bypass the post-rewrite hook.
+
-i::
--include::
Before making a commit out of staged contents so far,
more than two parents (affectionately called an Octopus merge).
+
If no commit is given from the command line, and if `merge.defaultToUpstream`
-configuration variable is set, merge the remote tracking branches
+configuration variable is set, merge the remote-tracking branches
that the current branch is configured to use as its upstream.
See also the configuration section of this manual page.
--recurse-submodules=check|on-demand::
Make sure all submodule commits used by the revisions to be
- pushed are available on a remote tracking branch. If 'check' is
+ pushed are available on a remote-tracking branch. If 'check' is
used git will verify that all submodule commits that changed in
the revisions to be pushed are available on at least one remote
of the submodule. If any commits are missing the push will be
records tip-of-the-tree commit objects of branches copied
from a remote repository.
+refs/replace/`<obj-sha1>`::
+ records the SHA1 of the object that replaces `<obj-sha1>`.
+ This is similar to info/grafts and is internally used and
+ maintained by linkgit:git-replace[1]. Such refs can be exchanged
+ between repositories while grafts are not.
+
packed-refs::
records the same information as refs/heads/, refs/tags/,
and friends record in a more efficient way. See
merge.defaultToUpstream::
If merge is called without any commit argument, merge the upstream
branches configured for the current branch by using their last
- observed values stored in their remote tracking branches.
+ observed values stored in their remote-tracking branches.
The values of the `branch.<current branch>.merge` that name the
branches at the remote named by `branch.<current branch>.remote`
are consulted, and then they are mapped via `remote.<remote>.fetch`
- to their corresponding remote tracking branches, and the tips of
+ to their corresponding remote-tracking branches, and the tips of
these tracking branches are merged.
merge.ff::
-Documentation/RelNotes/1.8.0.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.0.1.txt
\ No newline at end of file
return merged;
}
+static int check_branch_commit(const char *branchname, const char *refname,
+ unsigned char *sha1, struct commit *head_rev,
+ int kinds, int force)
+{
+ struct commit *rev = lookup_commit_reference(sha1);
+ if (!rev) {
+ error(_("Couldn't look up commit object for '%s'"), refname);
+ return -1;
+ }
+ if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
+ error(_("The branch '%s' is not fully merged.\n"
+ "If you are sure you want to delete it, "
+ "run 'git branch -D %s'."), branchname, branchname);
+ return -1;
+ }
+ return 0;
+}
+
+static void delete_branch_config(const char *branchname)
+{
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_addf(&buf, "branch.%s", branchname);
+ if (git_config_rename_section(buf.buf, NULL) < 0)
+ warning(_("Update of config-file failed"));
+ strbuf_release(&buf);
+}
+
static int delete_branches(int argc, const char **argv, int force, int kinds,
int quiet)
{
- struct commit *rev, *head_rev = NULL;
+ struct commit *head_rev = NULL;
unsigned char sha1[20];
char *name = NULL;
const char *fmt;
die(_("Couldn't look up commit object for HEAD"));
}
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
+ const char *target;
+ int flags = 0;
+
strbuf_branchname(&bname, argv[i]);
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
error(_("Cannot delete the branch '%s' "
free(name);
name = mkpathdup(fmt, bname.buf);
- if (read_ref(name, sha1)) {
+ target = resolve_ref_unsafe(name, sha1, 0, &flags);
+ if (!target ||
+ (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
error(remote_branch
? _("remote branch '%s' not found.")
: _("branch '%s' not found."), bname.buf);
continue;
}
- rev = lookup_commit_reference(sha1);
- if (!rev) {
- error(_("Couldn't look up commit object for '%s'"), name);
- ret = 1;
- continue;
- }
-
- if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
- error(_("The branch '%s' is not fully merged.\n"
- "If you are sure you want to delete it, "
- "run 'git branch -D %s'."), bname.buf, bname.buf);
+ if (!(flags & REF_ISSYMREF) &&
+ check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
+ force)) {
ret = 1;
continue;
}
- if (delete_ref(name, sha1, 0)) {
+ if (delete_ref(name, sha1, REF_NODEREF)) {
error(remote_branch
? _("Error deleting remote branch '%s'")
: _("Error deleting branch '%s'"),
bname.buf);
ret = 1;
- } else {
- struct strbuf buf = STRBUF_INIT;
- if (!quiet)
- printf(remote_branch
- ? _("Deleted remote branch %s (was %s).\n")
- : _("Deleted branch %s (was %s).\n"),
- bname.buf,
- find_unique_abbrev(sha1, DEFAULT_ABBREV));
- strbuf_addf(&buf, "branch.%s", bname.buf);
- if (git_config_rename_section(buf.buf, NULL) < 0)
- warning(_("Update of config-file failed"));
- strbuf_release(&buf);
+ continue;
+ }
+ if (!quiet) {
+ printf(remote_branch
+ ? _("Deleted remote branch %s (was %s).\n")
+ : _("Deleted branch %s (was %s).\n"),
+ bname.buf,
+ (flags & REF_ISSYMREF)
+ ? target
+ : find_unique_abbrev(sha1, DEFAULT_ABBREV));
}
+ delete_branch_config(bname.buf);
}
free(name);
else
sprintf(value, "%d", v);
} else if (types == TYPE_PATH) {
- git_config_pathname(&vptr, key_, value_);
+ if (git_config_pathname(&vptr, key_, value_) < 0)
+ return -1;
must_free_vptr = 1;
} else if (value_) {
vptr = value_;
static int skip_first_line;
static void add_work(struct grep_opt *opt, enum grep_source_type type,
- const char *name, const void *id)
+ const char *name, const char *path, const void *id)
{
grep_lock();
pthread_cond_wait(&cond_write, &grep_mutex);
}
- grep_source_init(&todo[todo_end].source, type, name, id);
+ grep_source_init(&todo[todo_end].source, type, name, path, id);
if (opt->binary != GREP_BINARY_TEXT)
grep_source_load_driver(&todo[todo_end].source);
todo[todo_end].done = 0;
}
#endif
-static int parse_pattern_type_arg(const char *opt, const char *arg)
+static int grep_cmd_config(const char *var, const char *value, void *cb)
{
- if (!strcmp(arg, "default"))
- return GREP_PATTERN_TYPE_UNSPECIFIED;
- else if (!strcmp(arg, "basic"))
- return GREP_PATTERN_TYPE_BRE;
- else if (!strcmp(arg, "extended"))
- return GREP_PATTERN_TYPE_ERE;
- else if (!strcmp(arg, "fixed"))
- return GREP_PATTERN_TYPE_FIXED;
- else if (!strcmp(arg, "perl"))
- return GREP_PATTERN_TYPE_PCRE;
- die("bad %s argument: %s", opt, arg);
-}
-
-static void grep_pattern_type_options(const int pattern_type, struct grep_opt *opt)
-{
- switch (pattern_type) {
- case GREP_PATTERN_TYPE_UNSPECIFIED:
- /* fall through */
-
- case GREP_PATTERN_TYPE_BRE:
- opt->fixed = 0;
- opt->pcre = 0;
- opt->regflags &= ~REG_EXTENDED;
- break;
-
- case GREP_PATTERN_TYPE_ERE:
- opt->fixed = 0;
- opt->pcre = 0;
- opt->regflags |= REG_EXTENDED;
- break;
-
- case GREP_PATTERN_TYPE_FIXED:
- opt->fixed = 1;
- opt->pcre = 0;
- opt->regflags &= ~REG_EXTENDED;
- break;
-
- case GREP_PATTERN_TYPE_PCRE:
- opt->fixed = 0;
- opt->pcre = 1;
- opt->regflags &= ~REG_EXTENDED;
- break;
- }
-}
-
-static int grep_config(const char *var, const char *value, void *cb)
-{
- struct grep_opt *opt = cb;
- char *color = NULL;
-
- if (userdiff_config(var, value) < 0)
- return -1;
-
- if (!strcmp(var, "grep.extendedregexp")) {
- if (git_config_bool(var, value))
- opt->extended_regexp_option = 1;
- else
- opt->extended_regexp_option = 0;
- return 0;
- }
-
- if (!strcmp(var, "grep.patterntype")) {
- opt->pattern_type_option = parse_pattern_type_arg(var, value);
- return 0;
- }
-
- if (!strcmp(var, "grep.linenumber")) {
- opt->linenum = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "color.grep"))
- opt->color = git_config_colorbool(var, value);
- else if (!strcmp(var, "color.grep.context"))
- color = opt->color_context;
- else if (!strcmp(var, "color.grep.filename"))
- color = opt->color_filename;
- else if (!strcmp(var, "color.grep.function"))
- color = opt->color_function;
- else if (!strcmp(var, "color.grep.linenumber"))
- color = opt->color_lineno;
- else if (!strcmp(var, "color.grep.match"))
- color = opt->color_match;
- else if (!strcmp(var, "color.grep.selected"))
- color = opt->color_selected;
- else if (!strcmp(var, "color.grep.separator"))
- color = opt->color_sep;
- else
- return git_color_default_config(var, value, cb);
- if (color) {
- if (!value)
- return config_error_nonbool(var);
- color_parse(value, var, color);
- }
- return 0;
+ int st = grep_config(var, value, cb);
+ if (git_color_default_config(var, value, cb) < 0)
+ st = -1;
+ return st;
}
static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
}
static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
- const char *filename, int tree_name_len)
+ const char *filename, int tree_name_len,
+ const char *path)
{
struct strbuf pathbuf = STRBUF_INIT;
#ifndef NO_PTHREADS
if (use_threads) {
- add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+ add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
strbuf_release(&pathbuf);
return 0;
} else
struct grep_source gs;
int hit;
- grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+ grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
strbuf_release(&pathbuf);
hit = grep_source(opt, &gs);
#ifndef NO_PTHREADS
if (use_threads) {
- add_work(opt, GREP_SOURCE_FILE, buf.buf, filename);
+ add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
strbuf_release(&buf);
return 0;
} else
struct grep_source gs;
int hit;
- grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename);
+ grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
strbuf_release(&buf);
hit = grep_source(opt, &gs);
if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
if (ce_stage(ce))
continue;
- hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
+ hit |= grep_sha1(opt, ce->sha1, ce->name, 0, ce->name);
}
else
hit |= grep_file(opt, ce->name);
}
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
- struct tree_desc *tree, struct strbuf *base, int tn_len)
+ struct tree_desc *tree, struct strbuf *base, int tn_len,
+ int check_attr)
{
int hit = 0;
enum interesting match = entry_not_interesting;
strbuf_add(base, entry.path, te_len);
if (S_ISREG(entry.mode)) {
- hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
+ hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len,
+ check_attr ? base->buf + tn_len : NULL);
}
else if (S_ISDIR(entry.mode)) {
enum object_type type;
strbuf_addch(base, '/');
init_tree_desc(&sub, data, size);
- hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
+ hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
+ check_attr);
free(data);
}
strbuf_setlen(base, old_baselen);
struct object *obj, const char *name)
{
if (obj->type == OBJ_BLOB)
- return grep_sha1(opt, obj->sha1, name, 0);
+ return grep_sha1(opt, obj->sha1, name, 0, NULL);
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
struct tree_desc tree;
void *data;
strbuf_addch(&base, ':');
}
init_tree_desc(&tree, data, size);
- hit = grep_tree(opt, pathspec, &tree, &base, base.len);
+ hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+ obj->type == OBJ_COMMIT);
strbuf_release(&base);
free(data);
return hit;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(grep_usage, options);
- memset(&opt, 0, sizeof(opt));
- opt.prefix = prefix;
- opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
- opt.relative = 1;
- opt.pathname = 1;
- opt.pattern_tail = &opt.pattern_list;
- opt.header_tail = &opt.header_list;
- opt.regflags = REG_NEWLINE;
- opt.max_depth = -1;
- opt.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
- opt.extended_regexp_option = 0;
-
- strcpy(opt.color_context, "");
- strcpy(opt.color_filename, "");
- strcpy(opt.color_function, "");
- strcpy(opt.color_lineno, "");
- strcpy(opt.color_match, GIT_COLOR_BOLD_RED);
- strcpy(opt.color_selected, "");
- strcpy(opt.color_sep, GIT_COLOR_CYAN);
- opt.color = -1;
- git_config(grep_config, &opt);
+ init_grep_defaults();
+ git_config(grep_cmd_config, NULL);
+ grep_init(&opt, prefix);
/*
* If there is no -- then the paths must exist in the working
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
-
- if (pattern_type_arg != GREP_PATTERN_TYPE_UNSPECIFIED)
- grep_pattern_type_options(pattern_type_arg, &opt);
- else if (opt.pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
- grep_pattern_type_options(opt.pattern_type_option, &opt);
- else if (opt.extended_regexp_option)
- grep_pattern_type_options(GREP_PATTERN_TYPE_ERE, &opt);
+ grep_commit_pattern_type(pattern_type_arg, &opt);
if (use_index && !startup_info->have_repository)
/* die the same way as if we did it at the beginning */
#include "strbuf.h"
#include "quote.h"
-#define MAXNAME (256)
-
typedef struct config_file {
struct config_file *prev;
FILE *f;
int linenr;
int eof;
struct strbuf value;
- char var[MAXNAME];
+ struct strbuf var;
} config_file;
static config_file *cf;
return isalnum(c) || c == '-';
}
-static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
+static int get_value(config_fn_t fn, void *data, struct strbuf *name)
{
int c;
char *value;
break;
if (!iskeychar(c))
break;
- name[len++] = tolower(c);
- if (len >= MAXNAME)
- return -1;
+ strbuf_addch(name, tolower(c));
}
- name[len] = 0;
+
while (c == ' ' || c == '\t')
c = get_next_char();
if (!value)
return -1;
}
- return fn(name, value, data);
+ return fn(name->buf, value, data);
}
-static int get_extended_base_var(char *name, int baselen, int c)
+static int get_extended_base_var(struct strbuf *name, int c)
{
do {
if (c == '\n')
/* We require the format to be '[base "extension"]' */
if (c != '"')
return -1;
- name[baselen++] = '.';
+ strbuf_addch(name, '.');
for (;;) {
int c = get_next_char();
if (c == '\n')
goto error_incomplete_line;
}
- name[baselen++] = c;
- if (baselen > MAXNAME / 2)
- return -1;
+ strbuf_addch(name, c);
}
/* Final ']' */
if (get_next_char() != ']')
return -1;
- return baselen;
+ return 0;
error_incomplete_line:
cf->linenr--;
return -1;
}
-static int get_base_var(char *name)
+static int get_base_var(struct strbuf *name)
{
- int baselen = 0;
-
for (;;) {
int c = get_next_char();
if (cf->eof)
return -1;
if (c == ']')
- return baselen;
+ return 0;
if (isspace(c))
- return get_extended_base_var(name, baselen, c);
+ return get_extended_base_var(name, c);
if (!iskeychar(c) && c != '.')
return -1;
- if (baselen > MAXNAME / 2)
- return -1;
- name[baselen++] = tolower(c);
+ strbuf_addch(name, tolower(c));
}
}
{
int comment = 0;
int baselen = 0;
- char *var = cf->var;
+ struct strbuf *var = &cf->var;
/* U+FEFF Byte Order Mark in UTF8 */
static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
continue;
}
if (c == '[') {
- baselen = get_base_var(var);
- if (baselen <= 0)
+ /* Reset prior to determining a new stem */
+ strbuf_reset(var);
+ if (get_base_var(var) < 0 || var->len < 1)
break;
- var[baselen++] = '.';
- var[baselen] = 0;
+ strbuf_addch(var, '.');
+ baselen = var->len;
continue;
}
if (!isalpha(c))
break;
- var[baselen] = tolower(c);
- if (get_value(fn, data, var, baselen+1) < 0)
+ /*
+ * Truncate the var name back to the section header
+ * stem prior to grabbing the suffix part of the name
+ * and the value.
+ */
+ strbuf_setlen(var, baselen);
+ strbuf_addch(var, tolower(c));
+ if (get_value(fn, data, var) < 0)
break;
}
die("bad config file line %d in %s", cf->linenr, cf->name);
top.linenr = 1;
top.eof = 0;
strbuf_init(&top.value, 1024);
+ strbuf_init(&top.var, 1024);
cf = ⊤
ret = git_parse_file(fn, data);
/* pop config-file parsing state stack */
strbuf_release(&top.value);
+ strbuf_release(&top.var);
cf = top.prev;
fclose(f);
if [[ "$ref" == "$cur"* ]]; then
echo "$ref"
fi
- done | uniq -u
+ done | sort | uniq -u
fi
return
fi
if (!mf2.ptr)
return 0; /* ignore unmerged */
/* created "two" -- does it have what we are looking for? */
- hit = !regexec(regexp, p->two->data, 1, ®match, 0);
+ hit = !regexec(regexp, mf2.ptr, 1, ®match, 0);
} else if (!mf2.ptr) {
/* removed "one" -- did it have what we are looking for? */
- hit = !regexec(regexp, p->one->data, 1, ®match, 0);
+ hit = !regexec(regexp, mf1.ptr, 1, ®match, 0);
} else {
/*
* We have both sides; need to run textual diff and see if
#undef isdigit
#undef isalpha
#undef isalnum
+#undef isprint
#undef islower
#undef isupper
#undef tolower
#define isdigit(x) sane_istest(x,GIT_DIGIT)
#define isalpha(x) sane_istest(x,GIT_ALPHA)
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e)
#define islower(x) sane_iscase(x, 1)
#define isupper(x) sane_iscase(x, 0)
#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
If you wish to set tracking information for this branch you can do so with:
- git branch --set-upstream ${branch_name#refs/heads/} $remote/<branch>
+ git branch --set-upstream-to=$remote/<branch> ${branch_name#refs/heads/}
"
fi
exit 1
require_clean_work_tree "pull with rebase" "Please commit or stash them."
fi
oldremoteref= &&
+ test -n "$curr_branch" &&
. git-parse-remote &&
remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
oldremoteref="$(git rev-parse -q --verify "$remoteref")" &&
$feed_type = 'history';
}
$title .= " $feed_type";
+ $title = esc_html($title);
my $descr = git_get_project_description($project);
if (defined $descr) {
$descr = esc_html($descr);
static int grep_source_load(struct grep_source *gs);
static int grep_source_is_binary(struct grep_source *gs);
+static struct grep_opt grep_defaults;
+
+/*
+ * Initialize the grep_defaults template with hardcoded defaults.
+ * We could let the compiler do this, but without C99 initializers
+ * the code gets unwieldy and unreadable, so...
+ */
+void init_grep_defaults(void)
+{
+ struct grep_opt *opt = &grep_defaults;
+ static int run_once;
+
+ if (run_once)
+ return;
+ run_once++;
+
+ memset(opt, 0, sizeof(*opt));
+ opt->relative = 1;
+ opt->pathname = 1;
+ opt->regflags = REG_NEWLINE;
+ opt->max_depth = -1;
+ opt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
+ opt->extended_regexp_option = 0;
+ strcpy(opt->color_context, "");
+ strcpy(opt->color_filename, "");
+ strcpy(opt->color_function, "");
+ strcpy(opt->color_lineno, "");
+ strcpy(opt->color_match, GIT_COLOR_BOLD_RED);
+ strcpy(opt->color_selected, "");
+ strcpy(opt->color_sep, GIT_COLOR_CYAN);
+ opt->color = -1;
+}
+
+static int parse_pattern_type_arg(const char *opt, const char *arg)
+{
+ if (!strcmp(arg, "default"))
+ return GREP_PATTERN_TYPE_UNSPECIFIED;
+ else if (!strcmp(arg, "basic"))
+ return GREP_PATTERN_TYPE_BRE;
+ else if (!strcmp(arg, "extended"))
+ return GREP_PATTERN_TYPE_ERE;
+ else if (!strcmp(arg, "fixed"))
+ return GREP_PATTERN_TYPE_FIXED;
+ else if (!strcmp(arg, "perl"))
+ return GREP_PATTERN_TYPE_PCRE;
+ die("bad %s argument: %s", opt, arg);
+}
+
+/*
+ * Read the configuration file once and store it in
+ * the grep_defaults template.
+ */
+int grep_config(const char *var, const char *value, void *cb)
+{
+ struct grep_opt *opt = &grep_defaults;
+ char *color = NULL;
+
+ if (userdiff_config(var, value) < 0)
+ return -1;
+
+ if (!strcmp(var, "grep.extendedregexp")) {
+ if (git_config_bool(var, value))
+ opt->extended_regexp_option = 1;
+ else
+ opt->extended_regexp_option = 0;
+ return 0;
+ }
+
+ if (!strcmp(var, "grep.patterntype")) {
+ opt->pattern_type_option = parse_pattern_type_arg(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "grep.linenumber")) {
+ opt->linenum = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "color.grep"))
+ opt->color = git_config_colorbool(var, value);
+ else if (!strcmp(var, "color.grep.context"))
+ color = opt->color_context;
+ else if (!strcmp(var, "color.grep.filename"))
+ color = opt->color_filename;
+ else if (!strcmp(var, "color.grep.function"))
+ color = opt->color_function;
+ else if (!strcmp(var, "color.grep.linenumber"))
+ color = opt->color_lineno;
+ else if (!strcmp(var, "color.grep.match"))
+ color = opt->color_match;
+ else if (!strcmp(var, "color.grep.selected"))
+ color = opt->color_selected;
+ else if (!strcmp(var, "color.grep.separator"))
+ color = opt->color_sep;
+
+ if (color) {
+ if (!value)
+ return config_error_nonbool(var);
+ color_parse(value, var, color);
+ }
+ return 0;
+}
+
+/*
+ * Initialize one instance of grep_opt and copy the
+ * default values from the template we read the configuration
+ * information in an earlier call to git_config(grep_config).
+ */
+void grep_init(struct grep_opt *opt, const char *prefix)
+{
+ struct grep_opt *def = &grep_defaults;
+
+ memset(opt, 0, sizeof(*opt));
+ opt->prefix = prefix;
+ opt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
+ opt->pattern_tail = &opt->pattern_list;
+ opt->header_tail = &opt->header_list;
+
+ opt->color = def->color;
+ opt->extended_regexp_option = def->extended_regexp_option;
+ opt->pattern_type_option = def->pattern_type_option;
+ opt->linenum = def->linenum;
+ opt->max_depth = def->max_depth;
+ opt->pathname = def->pathname;
+ opt->regflags = def->regflags;
+ opt->relative = def->relative;
+
+ strcpy(opt->color_context, def->color_context);
+ strcpy(opt->color_filename, def->color_filename);
+ strcpy(opt->color_function, def->color_function);
+ strcpy(opt->color_lineno, def->color_lineno);
+ strcpy(opt->color_match, def->color_match);
+ strcpy(opt->color_selected, def->color_selected);
+ strcpy(opt->color_sep, def->color_sep);
+}
+
+void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)
+{
+ if (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)
+ grep_set_pattern_type_option(pattern_type, opt);
+ else if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
+ grep_set_pattern_type_option(opt->pattern_type_option, opt);
+ else if (opt->extended_regexp_option)
+ grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);
+}
+
+void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
+{
+ switch (pattern_type) {
+ case GREP_PATTERN_TYPE_UNSPECIFIED:
+ /* fall through */
+
+ case GREP_PATTERN_TYPE_BRE:
+ opt->fixed = 0;
+ opt->pcre = 0;
+ opt->regflags &= ~REG_EXTENDED;
+ break;
+
+ case GREP_PATTERN_TYPE_ERE:
+ opt->fixed = 0;
+ opt->pcre = 0;
+ opt->regflags |= REG_EXTENDED;
+ break;
+
+ case GREP_PATTERN_TYPE_FIXED:
+ opt->fixed = 1;
+ opt->pcre = 0;
+ opt->regflags &= ~REG_EXTENDED;
+ break;
+
+ case GREP_PATTERN_TYPE_PCRE:
+ opt->fixed = 0;
+ opt->pcre = 1;
+ opt->regflags &= ~REG_EXTENDED;
+ break;
+ }
+}
static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
const char *origin, int no,
struct grep_source gs;
int r;
- grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL);
+ grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL, NULL);
gs.buf = buf;
gs.size = size;
}
void grep_source_init(struct grep_source *gs, enum grep_source_type type,
- const char *name, const void *identifier)
+ const char *name, const char *path,
+ const void *identifier)
{
gs->type = type;
gs->name = name ? xstrdup(name) : NULL;
+ gs->path = path ? xstrdup(path) : NULL;
gs->buf = NULL;
gs->size = 0;
gs->driver = NULL;
{
free(gs->name);
gs->name = NULL;
+ free(gs->path);
+ gs->path = NULL;
free(gs->identifier);
gs->identifier = NULL;
grep_source_clear_data(gs);
return;
grep_attr_lock();
- gs->driver = userdiff_find_by_path(gs->name);
+ if (gs->path)
+ gs->driver = userdiff_find_by_path(gs->path);
if (!gs->driver)
gs->driver = userdiff_find_by_name("default");
grep_attr_unlock();
void *output_priv;
};
+extern void init_grep_defaults(void);
+extern int grep_config(const char *var, const char *value, void *);
+extern void grep_init(struct grep_opt *, const char *prefix);
+void grep_set_pattern_type_option(enum grep_pattern_type, struct grep_opt *opt);
+void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
+
extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
char *buf;
unsigned long size;
+ char *path; /* for attribute lookups */
struct userdiff_driver *driver;
};
void grep_source_init(struct grep_source *gs, enum grep_source_type type,
- const char *name, const void *identifier);
+ const char *name, const char *path,
+ const void *identifier);
void grep_source_clear_data(struct grep_source *gs);
void grep_source_clear(struct grep_source *gs);
void grep_source_load_driver(struct grep_source *gs);
FD_ZERO(&excfds);
curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
+ /*
+ * It can happen that curl_multi_timeout returns a pathologically
+ * long timeout when curl_multi_fdset returns no file descriptors
+ * to read. See commit message for more details.
+ */
+ if (max_fd < 0 &&
+ (select_timeout.tv_sec > 0 ||
+ select_timeout.tv_usec > 50000)) {
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = 50000;
+ }
+
select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
}
}
while (isspace(*nstart) && nstart < left)
++nstart;
nend = left-1;
- while (isspace(*nend) && nend > nstart)
+ while (nend > nstart && isspace(*nend))
--nend;
*name = (nstart < nend ? nstart : NULL);
diff_cmd () {
+ # p4merge does not like /dev/null
+ rm_local=
+ rm_remote=
+ if test "/dev/null" = "$LOCAL"
+ then
+ LOCAL="./p4merge-dev-null.LOCAL.$$"
+ >"$LOCAL"
+ rm_local=true
+ fi
+ if test "/dev/null" = "$REMOTE"
+ then
+ REMOTE="./p4merge-dev-null.REMOTE.$$"
+ >"$REMOTE"
+ rm_remote=true
+ fi
+
"$merge_tool_path" "$LOCAL" "$REMOTE"
+
+ if test -n "$rm_local"
+ then
+ rm -f "$LOCAL"
+ fi
+ if test -n "$rm_remote"
+ then
+ rm -f "$REMOTE"
+ fi
}
merge_cmd () {
}
}
-static int has_rfc822_specials(const char *s, int len)
+static int needs_rfc822_quoting(const char *s, int len)
{
int i;
for (i = 0; i < len; i++)
return 0;
}
+static int last_line_length(struct strbuf *sb)
+{
+ int i;
+
+ /* How many bytes are already used on the last line? */
+ for (i = sb->len - 1; i >= 0; i--)
+ if (sb->buf[i] == '\n')
+ break;
+ return sb->len - (i + 1);
+}
+
static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
{
int i;
strbuf_addch(out, '"');
}
-static int is_rfc2047_special(char ch)
+enum rfc2047_type {
+ RFC2047_SUBJECT,
+ RFC2047_ADDRESS,
+};
+
+static int is_rfc2047_special(char ch, enum rfc2047_type type)
{
- return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
+ /*
+ * rfc2047, section 4.2:
+ *
+ * 8-bit values which correspond to printable ASCII characters other
+ * than "=", "?", and "_" (underscore), MAY be represented as those
+ * characters. (But see section 5 for restrictions.) In
+ * particular, SPACE and TAB MUST NOT be represented as themselves
+ * within encoded words.
+ */
+
+ /*
+ * rule out non-ASCII characters and non-printable characters (the
+ * non-ASCII check should be redundant as isprint() is not localized
+ * and only knows about ASCII, but be defensive about that)
+ */
+ if (non_ascii(ch) || !isprint(ch))
+ return 1;
+
+ /*
+ * rule out special printable characters (' ' should be the only
+ * whitespace character considered printable, but be defensive and use
+ * isspace())
+ */
+ if (isspace(ch) || ch == '=' || ch == '?' || ch == '_')
+ return 1;
+
+ /*
+ * rfc2047, section 5.3:
+ *
+ * As a replacement for a 'word' entity within a 'phrase', for example,
+ * one that precedes an address in a From, To, or Cc header. The ABNF
+ * definition for 'phrase' from RFC 822 thus becomes:
+ *
+ * phrase = 1*( encoded-word / word )
+ *
+ * In this case the set of characters that may be used in a "Q"-encoded
+ * 'encoded-word' is restricted to: <upper and lower case ASCII
+ * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
+ * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a
+ * 'phrase' MUST be separated from any adjacent 'word', 'text' or
+ * 'special' by 'linear-white-space'.
+ */
+
+ if (type != RFC2047_ADDRESS)
+ return 0;
+
+ /* '=' and '_' are special cases and have been checked above */
+ return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/');
}
-static void add_rfc2047(struct strbuf *sb, const char *line, int len,
- const char *encoding)
+static int needs_rfc2047_encoding(const char *line, int len,
+ enum rfc2047_type type)
{
- static const int max_length = 78; /* per rfc2822 */
int i;
- int line_len;
-
- /* How many bytes are already used on the current line? */
- for (i = sb->len - 1; i >= 0; i--)
- if (sb->buf[i] == '\n')
- break;
- line_len = sb->len - (i+1);
for (i = 0; i < len; i++) {
int ch = line[i];
if (non_ascii(ch) || ch == '\n')
- goto needquote;
+ return 1;
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
- goto needquote;
+ return 1;
}
- strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
- return;
-needquote:
+ return 0;
+}
+
+static void add_rfc2047(struct strbuf *sb, const char *line, int len,
+ const char *encoding, enum rfc2047_type type)
+{
+ static const int max_encoded_length = 76; /* per rfc2047 */
+ int i;
+ int line_len = last_line_length(sb);
+
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
strbuf_addf(sb, "=?%s?q?", encoding);
line_len += strlen(encoding) + 5; /* 5 for =??q? */
for (i = 0; i < len; i++) {
unsigned ch = line[i] & 0xFF;
+ int is_special = is_rfc2047_special(ch, type);
+
+ /*
+ * According to RFC 2047, we could encode the special character
+ * ' ' (space) with '_' (underscore) for readability. But many
+ * programs do not understand this and just leave the
+ * underscore in place. Thus, we do nothing special here, which
+ * causes ' ' to be encoded as '=20', avoiding this problem.
+ */
- if (line_len >= max_length - 2) {
+ if (line_len + 2 + (is_special ? 3 : 1) > max_encoded_length) {
strbuf_addf(sb, "?=\n =?%s?q?", encoding);
line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
}
- /*
- * We encode ' ' using '=20' even though rfc2047
- * allows using '_' for readability. Unfortunately,
- * many programs do not understand this and just
- * leave the underscore in place.
- */
- if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
+ if (is_special) {
strbuf_addf(sb, "=%02X", ch);
line_len += 3;
- }
- else {
+ } else {
strbuf_addch(sb, ch);
line_len++;
}
const char *what, struct strbuf *sb,
const char *line, const char *encoding)
{
+ int max_length = 78; /* per rfc2822 */
char *date;
int namelen;
unsigned long time;
if (pp->fmt == CMIT_FMT_EMAIL) {
char *name_tail = strchr(line, '<');
int display_name_length;
- int final_line;
if (!name_tail)
return;
while (line < name_tail && isspace(name_tail[-1]))
name_tail--;
display_name_length = name_tail - line;
strbuf_addstr(sb, "From: ");
- if (!has_rfc822_specials(line, display_name_length)) {
- add_rfc2047(sb, line, display_name_length, encoding);
- } else {
+ if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {
+ add_rfc2047(sb, line, display_name_length,
+ encoding, RFC2047_ADDRESS);
+ max_length = 76; /* per rfc2047 */
+ } else if (needs_rfc822_quoting(line, display_name_length)) {
struct strbuf quoted = STRBUF_INIT;
add_rfc822_quoted("ed, line, display_name_length);
- add_rfc2047(sb, quoted.buf, quoted.len, encoding);
+ strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
+ -6, 1, max_length);
strbuf_release("ed);
+ } else {
+ strbuf_add_wrapped_bytes(sb, line, display_name_length,
+ -6, 1, max_length);
}
- for (final_line = 0; final_line < sb->len; final_line++)
- if (sb->buf[sb->len - final_line - 1] == '\n')
- break;
- if (namelen - display_name_length + final_line > 78) {
+ if (namelen - display_name_length + last_line_length(sb) > max_length) {
strbuf_addch(sb, '\n');
if (!isspace(name_tail[0]))
strbuf_addch(sb, ' ');
const char *encoding,
int need_8bit_cte)
{
+ static const int max_length = 78; /* per rfc2047 */
struct strbuf title;
strbuf_init(&title, 80);
strbuf_grow(sb, title.len + 1024);
if (pp->subject) {
strbuf_addstr(sb, pp->subject);
- add_rfc2047(sb, title.buf, title.len, encoding);
+ if (needs_rfc2047_encoding(title.buf, title.len, RFC2047_SUBJECT))
+ add_rfc2047(sb, title.buf, title.len,
+ encoding, RFC2047_SUBJECT);
+ else
+ strbuf_add_wrapped_bytes(sb, title.buf, title.len,
+ -last_line_length(sb), 1, max_length);
} else {
strbuf_addbuf(sb, &title);
}
struct ref_lock *lock;
int err, i = 0, ret = 0, flag = 0;
- lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
+ lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
if (!lock)
return 1;
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
/* loose */
- const char *path;
-
- if (!(delopt & REF_NODEREF)) {
- i = strlen(lock->lk->filename) - 5; /* .lock */
- lock->lk->filename[i] = 0;
- path = lock->lk->filename;
- } else {
- path = git_path("%s", refname);
- }
- err = unlink_or_warn(path);
+ i = strlen(lock->lk->filename) - 5; /* .lock */
+ lock->lk->filename[i] = 0;
+ err = unlink_or_warn(lock->lk->filename);
if (err && errno != ENOENT)
ret = 1;
- if (!(delopt & REF_NODEREF))
- lock->lk->filename[i] = '.';
+ lock->lk->filename[i] = '.';
}
/* removing the loose one could have resurrected an earlier
* packed one. Also, if it was not loose we need to repack
revs->commit_format = CMIT_FMT_DEFAULT;
+ init_grep_defaults();
+ grep_init(&revs->grep_filter, prefix);
revs->grep_filter.status_only = 1;
- revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list);
- revs->grep_filter.header_tail = &(revs->grep_filter.header_list);
revs->grep_filter.regflags = REG_NEWLINE;
diff_setup(&revs->diffopt);
} else if (!strcmp(arg, "--grep-debug")) {
revs->grep_filter.debug = 1;
} else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
- revs->grep_filter.regflags |= REG_EXTENDED;
+ grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, &revs->grep_filter);
} else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
revs->grep_filter.regflags |= REG_ICASE;
DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
} else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
- revs->grep_filter.fixed = 1;
+ grep_set_pattern_type_option(GREP_PATTERN_TYPE_FIXED, &revs->grep_filter);
} else if (!strcmp(arg, "--all-match")) {
revs->grep_filter.all_match = 1;
} else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
revs->diffopt.abbrev = revs->abbrev;
diff_setup_done(&revs->diffopt);
+ grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,
+ &revs->grep_filter);
compile_grep_patterns(&revs->grep_filter);
if (revs->reverse && revs->reflog_info)
test_cmp expect result
'
+test_expect_success 'get --path barfs on boolean variable' '
+ echo "[path]bool" >.git/config &&
+ test_must_fail git config --get --path path.bool
+'
+
cat > expect << EOF
[quote]
leading = " test"
"test $(git config branch.s.dummy) = Hello &&
test_must_fail git config branch.s/s/dummy"
+test_expect_success 'deleting a symref' '
+ git branch target &&
+ git symbolic-ref refs/heads/symref refs/heads/target &&
+ echo "Deleted branch symref (was refs/heads/target)." >expect &&
+ git branch -d symref >actual &&
+ test_path_is_file .git/refs/heads/target &&
+ test_path_is_missing .git/refs/heads/symref &&
+ test_i18ncmp expect actual
+'
+
+test_expect_success 'deleting a dangling symref' '
+ git symbolic-ref refs/heads/dangling-symref nowhere &&
+ test_path_is_file .git/refs/heads/dangling-symref &&
+ echo "Deleted branch dangling-symref (was nowhere)." >expect &&
+ git branch -d dangling-symref >actual &&
+ test_path_is_missing .git/refs/heads/dangling-symref &&
+ test_i18ncmp expect actual
+'
+
test_expect_success 'renaming a symref is not allowed' \
'
git symbolic-ref refs/heads/master2 refs/heads/master &&
test_expect_success 'extra headers' '
- git config format.headers "To: R. E. Cipient <rcipient@example.com>
+ git config format.headers "To: R E Cipient <rcipient@example.com>
" &&
- git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
+ git config --add format.headers "Cc: S E Cipient <scipient@example.com>
" &&
git format-patch --stdout master..side > patch2 &&
sed -e "/^\$/q" patch2 > hdrs2 &&
- grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 &&
- grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2
+ grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
+ grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
'
test_expect_success 'extra headers without newlines' '
- git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
- git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
+ git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
+ git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
git format-patch --stdout master..side >patch3 &&
sed -e "/^\$/q" patch3 > hdrs3 &&
- grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 &&
- grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3
+ grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
+ grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
'
test_expect_success 'extra headers with multiple To:s' '
- git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
- git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
+ git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
+ git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
git format-patch --stdout master..side > patch4 &&
sed -e "/^\$/q" patch4 > hdrs4 &&
- grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 &&
- grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4
+ grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
+ grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
'
-test_expect_success 'additional command line cc' '
+test_expect_success 'additional command line cc (ascii)' '
- git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
+ git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
+ git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
+ grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
+ grep "^ *S E Cipient <scipient@example.com>\$" patch5
+'
+
+test_expect_failure 'additional command line cc (rfc822)' '
+
+ git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
- grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch5 &&
- grep "^ *S. E. Cipient <scipient@example.com>\$" patch5
+ grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
+ grep "^ *"S. E. Cipient" <scipient@example.com>\$" patch5
'
test_expect_success 'command line headers' '
git config --unset-all format.headers &&
- git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
- grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6
+ git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
+ grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
'
test_expect_success 'configuration headers and command line headers' '
- git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
- git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
- grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 &&
- grep "^ *S. E. Cipient <scipient@example.com>\$" patch7
+ git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
+ git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
+ grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
+ grep "^ *S E Cipient <scipient@example.com>\$" patch7
'
-test_expect_success 'command line To: header' '
+test_expect_success 'command line To: header (ascii)' '
git config --unset-all format.headers &&
+ git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
+ grep "^To: R E Cipient <rcipient@example.com>\$" patch8
+'
+
+test_expect_failure 'command line To: header (rfc822)' '
+
git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
- grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8
+ grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch8
'
-test_expect_success 'configuration To: header' '
+test_expect_failure 'command line To: header (rfc2047)' '
+
+ git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
+ grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
+'
+
+test_expect_success 'configuration To: header (ascii)' '
+
+ git config format.to "R E Cipient <rcipient@example.com>" &&
+ git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
+ grep "^To: R E Cipient <rcipient@example.com>\$" patch9
+'
+
+test_expect_failure 'configuration To: header (rfc822)' '
git config format.to "R. E. Cipient <rcipient@example.com>" &&
git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
- grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9
+ grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch9
+'
+
+test_expect_failure 'configuration To: header (rfc2047)' '
+
+ git config format.to "R Ä Cipient <rcipient@example.com>" &&
+ git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
+ grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
'
# check_patch <patch>: Verify that <patch> looks like a half-sane
test_expect_success '--no-to overrides config.to' '
git config --replace-all format.to \
- "R. E. Cipient <rcipient@example.com>" &&
+ "R E Cipient <rcipient@example.com>" &&
git format-patch --no-to --stdout master..side |
sed -e "/^\$/q" >patch10 &&
check_patch patch10 &&
- ! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10
+ ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
'
test_expect_success '--no-to and --to replaces config.to' '
test_expect_success '--no-cc overrides config.cc' '
git config --replace-all format.cc \
- "C. E. Cipient <rcipient@example.com>" &&
+ "C E Cipient <rcipient@example.com>" &&
git format-patch --no-cc --stdout master..side |
sed -e "/^\$/q" >patch12 &&
check_patch patch12 &&
- ! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12
+ ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
'
test_expect_success '--no-add-header overrides config.headers' '
git config --replace-all format.headers \
- "Header1: B. E. Cipient <rcipient@example.com>" &&
+ "Header1: B E Cipient <rcipient@example.com>" &&
git format-patch --no-add-header --stdout master..side |
sed -e "/^\$/q" >patch13 &&
check_patch patch13 &&
- ! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13
+ ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
'
test_expect_success 'multiple files' '
M512=$M64$M64$M64$M64$M64$M64$M64$M64
cat >expect <<'EOF'
Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
EOF
-test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+test_expect_success 'format-patch wraps extremely long subject (ascii)' '
echo content >>file &&
git add file &&
git commit -m "$M512" &&
M64=$M8$M8$M8$M8$M8$M8$M8$M8
M512=$M64$M64$M64$M64$M64$M64$M64$M64
cat >expect <<'EOF'
-Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
EOF
-test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
rm -rf patches/ &&
echo content >>file &&
git add file &&
test_cmp expect subject
'
-M8="foo_bar_"
-M64=$M8$M8$M8$M8$M8$M8$M8$M8
-cat >expect <<EOF
-From: $M64
- <foobar@foo.bar>
-EOF
-test_expect_success 'format-patch wraps non-quotable headers' '
- rm -rf patches/ &&
- echo content >>file &&
- git add file &&
- git commit -mfoo --author "$M64 <foobar@foo.bar>" &&
- git format-patch --stdout -1 >patch &&
- sed -n "/^From: /p; /^ /p; /^$/q" <patch >from &&
- test_cmp expect from
-'
-
check_author() {
echo content >>file &&
git add file &&
GIT_AUTHOR_NAME=$1 git commit -m author-check &&
git format-patch --stdout -1 >patch &&
- grep ^From: patch >actual &&
+ sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
test_cmp expect actual
}
cat >expect <<'EOF'
From: "Foo B. Bar" <author@example.com>
EOF
-test_expect_success 'format-patch quotes dot in headers' '
+test_expect_success 'format-patch quotes dot in from-headers' '
check_author "Foo B. Bar"
'
cat >expect <<'EOF'
From: "Foo \"The Baz\" Bar" <author@example.com>
EOF
-test_expect_success 'format-patch quotes double-quote in headers' '
+test_expect_success 'format-patch quotes double-quote in from-headers' '
check_author "Foo \"The Baz\" Bar"
'
cat >expect <<'EOF'
-From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com>
+From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
+EOF
+test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
+ check_author "Föo Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
EOF
-test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' '
+test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
check_author "Föo B. Bar"
'
+cat >expect <<EOF
+From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
+ <author@example.com>
+EOF
+test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
+ check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
+'
+
+cat >expect <<'EOF'
+From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
+ Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
+ Bar Foo Bar Foo Bar Foo Bar <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
+ check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
+cat >expect <<'EOF'
+From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
+ Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
+ Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
+ check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
+ =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
+ =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
+ =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
+ =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
+ check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
cat >expect <<'EOF'
Subject: header with . in it
EOF
git reset --soft HEAD@{1}
'
+test_expect_success 'grep-diff (-G) operates on textconv data (add)' '
+ echo one >expect &&
+ git log --root --format=%s -G0 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep-diff (-G) operates on textconv data (modification)' '
+ echo two >expect &&
+ git log --root --format=%s -G1 >actual &&
+ test_cmp expect actual
+'
+
cat >expect.stat <<'EOF'
file | Bin 2 -> 4 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
commit.
EOF
-test_expect_success 'format %w(12,1,2)' '
+test_expect_success 'format %w(11,1,2)' '
- git log -2 --format="%w(12,1,2)This is the %s commit." > actual &&
+ git log -2 --format="%w(11,1,2)This is the %s commit." > actual &&
test_cmp expect actual
'
test_cmp expect actual
'
+test_expect_success 'log -F -E --grep=<ere> uses ere' '
+ echo second >expect &&
+ git log -1 --pretty="tformat:%s" -F -E --grep=s.c.nd >actual &&
+ test_cmp expect actual
+'
+
cat > expect <<EOF
* Second
* sixth
test_cmp expect actual
'
+test_expect_success 'grep --cached respects binary diff attribute' '
+ git grep --cached text t >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --cached respects binary diff attribute (2)' '
+ git add .gitattributes &&
+ rm .gitattributes &&
+ git grep --cached text t >actual &&
+ test_when_finished "git rm --cached .gitattributes" &&
+ test_when_finished "git checkout .gitattributes" &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep revision respects binary diff attribute' '
+ git commit -m new &&
+ echo "Binary file HEAD:t matches" >expect &&
+ git grep text HEAD -- t >actual &&
+ test_when_finished "git reset HEAD^" &&
+ test_cmp expect actual
+'
+
test_expect_success 'grep respects not-binary diff attribute' '
echo binQary | q_to_nul >b &&
git add b &&
test_cmp expected actual
'
+xss() {
+ echo >&2 "Checking $1..." &&
+ gitweb_run "$1" &&
+ if grep "$TAG" gitweb.body; then
+ echo >&2 "xss: $TAG should have been quoted in output"
+ return 1
+ fi
+ return 0
+}
+
+test_expect_success 'xss checks' '
+ TAG="<magic-xss-tag>" &&
+ xss "a=rss&p=$TAG" &&
+ xss "a=rss&p=foo.git&f=$TAG"
+'
test_done
say_color() {
test -z "$1" && test -n "$quiet" && return
shift
- echo "$*"
+ printf "%s\n" "$*"
}
fi
c = *text;
if (!c || isspace(c)) {
- if (w < width || !space) {
+ if (w <= width || !space) {
const char *start = bol;
if (!c && text == start)
return w;