diff options
-rw-r--r-- | Documentation/git-send-email.txt | 12 | ||||
-rw-r--r-- | Documentation/git-shortlog.txt | 40 | ||||
-rw-r--r-- | builtin-describe.c | 2 | ||||
-rw-r--r-- | builtin-merge-file.c | 7 | ||||
-rw-r--r-- | daemon.c | 56 | ||||
-rw-r--r-- | pretty.c | 119 | ||||
-rwxr-xr-x | t/t6120-describe.sh | 6 |
7 files changed, 145 insertions, 97 deletions
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 12788667d..b69846e52 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -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 ------------- diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index 7ccf31ccc..8f7c0e226 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -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: + +------------ +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: ------------ -# Keep alphabetized -Adam Morrow <adam@localhost.localdomain> -Eve Jones <eve@laptop.(none)> +# 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 diff --git a/builtin-describe.c b/builtin-describe.c index d2cfb1b08..3a007ed1c 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -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); } diff --git a/builtin-merge-file.c b/builtin-merge-file.c index 9d4e87480..96edb97a8 100644 --- a/builtin-merge-file.c +++ b/builtin-merge-file.c @@ -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]) @@ -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 */ @@ -440,19 +439,10 @@ 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; @@ -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) diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index e6c9e59b6..8c7e081c5 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -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 ' |