Merge branch 'maint'
* maint: git-send-email.txt: move --format-patch paragraph to a proper location git-shortlog.txt: improve documentation about .mailmap files pretty: support multiline subjects with format: pretty: factor out format_subject() pretty: factor out skip_empty_lines() merge-file: handle freopen() failure daemon: cleanup: factor out xstrdup_tolower() daemon: cleanup: replace loop with if daemon: handle freopen() failure describe: Avoid unnecessary warning when using --all
This commit is contained in:
commit
159c88e5ae
@ -197,12 +197,6 @@ Administering
|
||||
--[no-]validate::
|
||||
Perform sanity checks on patches.
|
||||
Currently, validation means the following:
|
||||
|
||||
--[no-]format-patch::
|
||||
When an argument may be understood either as a reference or as a file name,
|
||||
choose to understand it as a format-patch argument ('--format-patch')
|
||||
or as a file name ('--no-format-patch'). By default, when such a conflict
|
||||
occurs, git send-email will fail.
|
||||
+
|
||||
--
|
||||
* Warn of patches that contain lines longer than 998 characters; this
|
||||
@ -212,6 +206,12 @@ Administering
|
||||
Default is the value of 'sendemail.validate'; if this is not set,
|
||||
default to '--validate'.
|
||||
|
||||
--[no-]format-patch::
|
||||
When an argument may be understood either as a reference or as a file name,
|
||||
choose to understand it as a format-patch argument ('--format-patch')
|
||||
or as a file name ('--no-format-patch'). By default, when such a conflict
|
||||
occurs, git send-email will fail.
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
|
@ -48,15 +48,41 @@ OPTIONS
|
||||
FILES
|
||||
-----
|
||||
|
||||
If the file `.mailmap` exists, it will be used for mapping author
|
||||
email addresses to a real author name. One mapping per line, first
|
||||
the author name followed by the email address enclosed by
|
||||
'<' and '>'. Use hash '#' for comments. Example:
|
||||
If a file `.mailmap` exists at the toplevel of the repository,
|
||||
it is used to map an author email address to a canonical real name. This
|
||||
can be used to coalesce together commits by the same person where their
|
||||
name was spelled differently (whether with the same email address or
|
||||
not).
|
||||
|
||||
Each line in the file consists, in this order, of the canonical real name
|
||||
of an author, whitespace, and an email address (enclosed by '<' and '>')
|
||||
to map to the name. Use hash '#' for comments, either on their own line,
|
||||
or after the email address.
|
||||
|
||||
A canonical name may appear in more than one line, associated with
|
||||
different email addresses, but it doesn't make sense for a given address
|
||||
to appear more than once (if that happens, a later line overrides the
|
||||
earlier ones).
|
||||
|
||||
So, for example, if your history contains commits by two authors, Jane
|
||||
and Joe, whose names appear in the repository under several forms:
|
||||
|
||||
------------
|
||||
# Keep alphabetized
|
||||
Adam Morrow <adam@localhost.localdomain>
|
||||
Eve Jones <eve@laptop.(none)>
|
||||
Joe Developer <joe@example.com>
|
||||
Joe R. Developer <joe@example.com>
|
||||
Jane Doe <jane@example.com>
|
||||
Jane Doe <jane@laptop.(none)>
|
||||
Jane D. <jane@desktop.(none)>
|
||||
------------
|
||||
|
||||
Then, supposing Joe wants his middle name initial used, and Jane prefers
|
||||
her family name fully spelled out, a proper `.mailmap` file would look like:
|
||||
|
||||
------------
|
||||
# Note how we don't need an entry for <jane@laptop.(none)>, because the
|
||||
# real name of that author is correct already, and coalesced directly.
|
||||
Jane Doe <jane@desktop.(none)>
|
||||
Joe R. Developer <joe@random.com>
|
||||
------------
|
||||
|
||||
Author
|
||||
|
@ -158,7 +158,7 @@ static void display_name(struct commit_name *n)
|
||||
n->tag = lookup_tag(n->sha1);
|
||||
if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
|
||||
die("annotated tag %s not available", n->path);
|
||||
if (strcmp(n->tag->tag, n->path))
|
||||
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
|
||||
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,11 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
argc = parse_options(argc, argv, options, merge_file_usage, 0);
|
||||
if (argc != 3)
|
||||
usage_with_options(merge_file_usage, options);
|
||||
if (quiet)
|
||||
freopen("/dev/null", "w", stderr);
|
||||
if (quiet) {
|
||||
if (!freopen("/dev/null", "w", stderr))
|
||||
return error("failed to redirect stderr to /dev/null: "
|
||||
"%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!names[i])
|
||||
|
56
daemon.c
56
daemon.c
@ -150,7 +150,6 @@ static char *path_ok(char *directory)
|
||||
{
|
||||
static char rpath[PATH_MAX];
|
||||
static char interp_path[PATH_MAX];
|
||||
int retried_path = 0;
|
||||
char *path;
|
||||
char *dir;
|
||||
|
||||
@ -219,22 +218,15 @@ static char *path_ok(char *directory)
|
||||
dir = rpath;
|
||||
}
|
||||
|
||||
do {
|
||||
path = enter_repo(dir, strict_paths);
|
||||
if (path)
|
||||
break;
|
||||
|
||||
path = enter_repo(dir, strict_paths);
|
||||
if (!path && base_path && base_path_relaxed) {
|
||||
/*
|
||||
* if we fail and base_path_relaxed is enabled, try without
|
||||
* prefixing the base path
|
||||
*/
|
||||
if (base_path && base_path_relaxed && !retried_path) {
|
||||
dir = directory;
|
||||
retried_path = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while (1);
|
||||
dir = directory;
|
||||
path = enter_repo(dir, strict_paths);
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
logerror("'%s': unable to chdir or not a git archive", dir);
|
||||
@ -405,6 +397,14 @@ static void make_service_overridable(const char *name, int ena)
|
||||
die("No such service %s", name);
|
||||
}
|
||||
|
||||
static char *xstrdup_tolower(const char *str)
|
||||
{
|
||||
char *p, *dup = xstrdup(str);
|
||||
for (p = dup; *p; p++)
|
||||
*p = tolower(*p);
|
||||
return dup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Separate the "extra args" information as supplied by the client connection.
|
||||
*/
|
||||
@ -413,7 +413,6 @@ static void parse_extra_args(char *extra_args, int buflen)
|
||||
char *val;
|
||||
int vallen;
|
||||
char *end = extra_args + buflen;
|
||||
char *hp;
|
||||
|
||||
while (extra_args < end && *extra_args) {
|
||||
saw_extended_args = 1;
|
||||
@ -431,7 +430,7 @@ static void parse_extra_args(char *extra_args, int buflen)
|
||||
tcp_port = xstrdup(port);
|
||||
}
|
||||
free(hostname);
|
||||
hostname = xstrdup(host);
|
||||
hostname = xstrdup_tolower(host);
|
||||
}
|
||||
|
||||
/* On to the next one */
|
||||
@ -439,20 +438,11 @@ static void parse_extra_args(char *extra_args, int buflen)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace literal host with lowercase-ized hostname.
|
||||
*/
|
||||
hp = hostname;
|
||||
if (!hp)
|
||||
return;
|
||||
for ( ; *hp; hp++)
|
||||
*hp = tolower(*hp);
|
||||
|
||||
/*
|
||||
* Locate canonical hostname and its IP address.
|
||||
*/
|
||||
if (hostname) {
|
||||
#ifndef NO_IPV6
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *ai, *ai0;
|
||||
int gai;
|
||||
@ -476,9 +466,7 @@ static void parse_extra_args(char *extra_args, int buflen)
|
||||
}
|
||||
freeaddrinfo(ai0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct hostent *hent;
|
||||
struct sockaddr_in sa;
|
||||
char **ap;
|
||||
@ -499,8 +487,8 @@ static void parse_extra_args(char *extra_args, int buflen)
|
||||
canon_hostname = xstrdup(hent->h_name);
|
||||
free(ip_address);
|
||||
ip_address = xstrdup(addrbuf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -953,12 +941,8 @@ int main(int argc, char **argv)
|
||||
char *arg = argv[i];
|
||||
|
||||
if (!prefixcmp(arg, "--listen=")) {
|
||||
char *p = arg + 9;
|
||||
char *ph = listen_addr = xmalloc(strlen(arg + 9) + 1);
|
||||
while (*p)
|
||||
*ph++ = tolower(*p++);
|
||||
*ph = 0;
|
||||
continue;
|
||||
listen_addr = xstrdup_tolower(arg + 9);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--port=")) {
|
||||
char *end;
|
||||
@ -1118,7 +1102,9 @@ int main(int argc, char **argv)
|
||||
struct sockaddr *peer = (struct sockaddr *)&ss;
|
||||
socklen_t slen = sizeof(ss);
|
||||
|
||||
freopen("/dev/null", "w", stderr);
|
||||
if (!freopen("/dev/null", "w", stderr))
|
||||
die("failed to redirect stderr to /dev/null: %s",
|
||||
strerror(errno));
|
||||
|
||||
if (getpeername(0, peer, &slen))
|
||||
peer = NULL;
|
||||
|
119
pretty.c
119
pretty.c
@ -181,6 +181,20 @@ static int is_empty_line(const char *line, int *len_p)
|
||||
return !len;
|
||||
}
|
||||
|
||||
static const char *skip_empty_lines(const char *msg)
|
||||
{
|
||||
for (;;) {
|
||||
int linelen = get_one_line(msg);
|
||||
int ll = linelen;
|
||||
if (!linelen)
|
||||
break;
|
||||
if (!is_empty_line(msg, &ll))
|
||||
break;
|
||||
msg += linelen;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
|
||||
const struct commit *commit, int abbrev)
|
||||
{
|
||||
@ -410,13 +424,15 @@ struct chunk {
|
||||
struct format_commit_context {
|
||||
const struct commit *commit;
|
||||
enum date_mode dmode;
|
||||
unsigned commit_header_parsed:1;
|
||||
unsigned commit_message_parsed:1;
|
||||
|
||||
/* These offsets are relative to the start of the commit message. */
|
||||
int commit_header_parsed;
|
||||
struct chunk subject;
|
||||
struct chunk author;
|
||||
struct chunk committer;
|
||||
struct chunk encoding;
|
||||
size_t message_off;
|
||||
size_t subject_off;
|
||||
size_t body_off;
|
||||
|
||||
/* The following ones are relative to the result struct strbuf. */
|
||||
@ -446,23 +462,14 @@ static void parse_commit_header(struct format_commit_context *context)
|
||||
{
|
||||
const char *msg = context->commit->buffer;
|
||||
int i;
|
||||
enum { HEADER, SUBJECT, BODY } state;
|
||||
|
||||
for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
|
||||
for (i = 0; msg[i]; i++) {
|
||||
int eol;
|
||||
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
|
||||
; /* do nothing */
|
||||
|
||||
if (state == SUBJECT) {
|
||||
context->subject.off = i;
|
||||
context->subject.len = eol - i;
|
||||
i = eol;
|
||||
}
|
||||
if (i == eol) {
|
||||
state++;
|
||||
/* strip empty lines */
|
||||
while (msg[eol] == '\n' && msg[eol + 1] == '\n')
|
||||
eol++;
|
||||
break;
|
||||
} else if (!prefixcmp(msg + i, "author ")) {
|
||||
context->author.off = i + 7;
|
||||
context->author.len = eol - i - 7;
|
||||
@ -474,13 +481,50 @@ static void parse_commit_header(struct format_commit_context *context)
|
||||
context->encoding.len = eol - i - 9;
|
||||
}
|
||||
i = eol;
|
||||
if (!msg[i])
|
||||
break;
|
||||
}
|
||||
context->body_off = i;
|
||||
context->message_off = i;
|
||||
context->commit_header_parsed = 1;
|
||||
}
|
||||
|
||||
static const char *format_subject(struct strbuf *sb, const char *msg,
|
||||
const char *line_separator)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
for (;;) {
|
||||
const char *line = msg;
|
||||
int linelen = get_one_line(line);
|
||||
|
||||
msg += linelen;
|
||||
if (!linelen || is_empty_line(line, &linelen))
|
||||
break;
|
||||
|
||||
if (!sb)
|
||||
continue;
|
||||
strbuf_grow(sb, linelen + 2);
|
||||
if (!first)
|
||||
strbuf_addstr(sb, line_separator);
|
||||
strbuf_add(sb, line, linelen);
|
||||
first = 0;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void parse_commit_message(struct format_commit_context *c)
|
||||
{
|
||||
const char *msg = c->commit->buffer + c->message_off;
|
||||
const char *start = c->commit->buffer;
|
||||
|
||||
msg = skip_empty_lines(msg);
|
||||
c->subject_off = msg - start;
|
||||
|
||||
msg = format_subject(NULL, msg, NULL);
|
||||
msg = skip_empty_lines(msg);
|
||||
c->body_off = msg - start;
|
||||
|
||||
c->commit_message_parsed = 1;
|
||||
}
|
||||
|
||||
static void format_decoration(struct strbuf *sb, const struct commit *commit)
|
||||
{
|
||||
struct name_decoration *d;
|
||||
@ -600,9 +644,6 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
parse_commit_header(c);
|
||||
|
||||
switch (placeholder[0]) {
|
||||
case 's': /* subject */
|
||||
strbuf_add(sb, msg + c->subject.off, c->subject.len);
|
||||
return 1;
|
||||
case 'a': /* author ... */
|
||||
return format_person_part(sb, placeholder[1],
|
||||
msg + c->author.off, c->author.len,
|
||||
@ -614,6 +655,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
case 'e': /* encoding */
|
||||
strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Now we need to parse the commit message. */
|
||||
if (!c->commit_message_parsed)
|
||||
parse_commit_message(c);
|
||||
|
||||
switch (placeholder[0]) {
|
||||
case 's': /* subject */
|
||||
format_subject(sb, msg + c->subject_off, " ");
|
||||
return 1;
|
||||
case 'b': /* body */
|
||||
strbuf_addstr(sb, msg + c->body_off);
|
||||
return 1;
|
||||
@ -704,27 +755,11 @@ void pp_title_line(enum cmit_fmt fmt,
|
||||
const char *encoding,
|
||||
int need_8bit_cte)
|
||||
{
|
||||
const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
|
||||
struct strbuf title;
|
||||
|
||||
strbuf_init(&title, 80);
|
||||
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(line);
|
||||
|
||||
*msg_p += linelen;
|
||||
if (!linelen || is_empty_line(line, &linelen))
|
||||
break;
|
||||
|
||||
strbuf_grow(&title, linelen + 2);
|
||||
if (title.len) {
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
strbuf_addch(&title, '\n');
|
||||
}
|
||||
strbuf_addch(&title, ' ');
|
||||
}
|
||||
strbuf_add(&title, line, linelen);
|
||||
}
|
||||
*msg_p = format_subject(&title, *msg_p, line_separator);
|
||||
|
||||
strbuf_grow(sb, title.len + 1024);
|
||||
if (subject) {
|
||||
@ -850,15 +885,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
|
||||
}
|
||||
|
||||
/* Skip excess blank lines at the beginning of body, if any... */
|
||||
for (;;) {
|
||||
int linelen = get_one_line(msg);
|
||||
int ll = linelen;
|
||||
if (!linelen)
|
||||
break;
|
||||
if (!is_empty_line(msg, &ll))
|
||||
break;
|
||||
msg += linelen;
|
||||
}
|
||||
msg = skip_empty_lines(msg);
|
||||
|
||||
/* These formats treat the title line specially. */
|
||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||
|
@ -100,6 +100,12 @@ check_describe B --tags HEAD^^2^
|
||||
check_describe B-0-* --long HEAD^^2^
|
||||
check_describe A-3-* --long HEAD^^2
|
||||
|
||||
: >err.expect
|
||||
check_describe A --all A^0
|
||||
test_expect_success 'no warning was displayed for A' '
|
||||
test_cmp err.expect err.actual
|
||||
'
|
||||
|
||||
test_expect_success 'rename tag A to Q locally' '
|
||||
mv .git/refs/tags/A .git/refs/tags/Q
|
||||
'
|
||||
|
Loading…
Reference in New Issue
Block a user