From: Junio C Hamano Date: Wed, 20 Jan 2010 22:40:12 +0000 (-0800) Subject: Merge branch 'jk/warn-author-committer-after-commit' X-Git-Tag: v1.7.0-rc0~72 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0877510ad4e8b951b08f9cbb25cfc0d994468979?ds=inline;hp=-c Merge branch 'jk/warn-author-committer-after-commit' * jk/warn-author-committer-after-commit: user_ident_sufficiently_given(): refactor the logic to be usable from elsewhere commit.c::print_summary: do not release the format string too early commit: allow suppression of implicit identity advice commit: show interesting ident information in summary strbuf: add strbuf_addbuf_percentquote strbuf_expand: convert "%%" to "%" Conflicts: builtin-commit.c ident.c --- 0877510ad4e8b951b08f9cbb25cfc0d994468979 diff --combined Documentation/config.txt index 2d6775c135,6f70cc953e..d4332140a0 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@@ -130,6 -130,10 +130,10 @@@ advice.*: Advice shown when linkgit:git-merge[1] refuses to merge to avoid overwritting local changes. Default: true. + implicitIdentity:: + Advice on how to set your identity configuration when + your information is guessed from the system username and + domain name. Default: true. -- core.fileMode:: @@@ -297,24 -301,17 +301,24 @@@ false), while all other repositories ar = true). core.worktree:: - Set the path to the working tree. The value will not be - used in combination with repositories found automatically in - a .git directory (i.e. $GIT_DIR is not set). + Set the path to the root of the work tree. This can be overridden by the GIT_WORK_TREE environment variable and the '--work-tree' command line option. It can be - a absolute path or relative path to the directory specified by - --git-dir or GIT_DIR. - Note: If --git-dir or GIT_DIR are specified but none of + an absolute path or a relative path to the .git directory, + either specified by --git-dir or GIT_DIR, or automatically + discovered. + If --git-dir or GIT_DIR are specified but none of --work-tree, GIT_WORK_TREE and core.worktree is specified, - the current working directory is regarded as the top directory - of your working tree. + the current working directory is regarded as the root of the + work tree. ++ +Note that this variable is honored even when set in a configuration +file in a ".git" subdirectory of a directory, and its value differs +from the latter directory (e.g. "/path/to/.git/config" has +core.worktree set to "/different/path"), which is most likely a +misconfiguration. Running git commands in "/path/to" directory will +still use "/different/path" as the root of the work tree and can cause +great confusion to the users. core.logAllRefUpdates:: Enable the reflog. Updates to a ref is logged to the file @@@ -502,10 -499,6 +506,10 @@@ notes should be printed This setting defaults to "refs/notes/commits", and can be overridden by the `GIT_NOTES_REF` environment variable. +core.sparseCheckout:: + Enable "sparse checkout" feature. See section "Sparse checkout" in + linkgit:git-read-tree[1] for more information. + add.ignore-errors:: Tells 'git-add' to continue adding files when some files cannot be added due to indexing errors. Equivalent to the '--ignore-errors' @@@ -541,7 -534,7 +545,7 @@@ apply.whitespace: as the '--whitespace' option. See linkgit:git-apply[1]. branch.autosetupmerge:: - Tells 'git-branch' and 'git-checkout' to setup new branches + Tells 'git-branch' and 'git-checkout' to set up new branches so that linkgit:git-pull[1] will appropriately merge from the starting point branch. Note that even if this option is not set, this behavior can be chosen per-branch using the `--track` @@@ -716,11 -709,6 +720,11 @@@ color.ui: terminal. When more specific variables of color.* are set, they always take precedence over this setting. Defaults to false. +commit.status + A boolean to enable/disable inclusion of status information in the + commit message template when using an editor to prepare the commit + message. Defaults to true. + commit.template:: Specify a file to use as the template for new commit messages. "{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the @@@ -734,7 -722,7 +738,7 @@@ diff.autorefreshindex: contents in the work tree match the contents in the index. This option defaults to true. Note that this affects only 'git-diff' Porcelain, and not lower level - 'diff' commands, such as 'git-diff-files'. + 'diff' commands such as 'git-diff-files'. diff.external:: If this config variable is set, diff generation is not @@@ -850,8 -838,8 +854,8 @@@ format.pretty: format.thread:: The default threading style for 'git-format-patch'. Can be - either a boolean value, `shallow` or `deep`. `shallow` - threading makes every mail a reply to the head of the series, + a boolean value, or `shallow` or `deep`. `shallow` threading + makes every mail a reply to the head of the series, where the head is chosen from the cover letter, the `\--in-reply-to`, and the first patch mail, in this order. `deep` threading makes every mail a reply to the previous one. @@@ -884,12 -872,15 +888,12 @@@ gc.autopacklimit: default value is 50. Setting this to 0 disables it. gc.packrefs:: - 'git-gc' does not run `git pack-refs` in a bare repository by - default so that older dumb-transport clients can still fetch - from the repository. Setting this to `true` lets 'git-gc' - to run `git pack-refs`. Setting this to `false` tells - 'git-gc' never to run `git pack-refs`. The default setting is - `notbare`. Enable it only when you know you do not have to - support such clients. The default setting will change to `true` - at some stage, and setting this to `false` will continue to - prevent `git pack-refs` from being run from 'git-gc'. + Running `git pack-refs` in a repository renders it + unclonable by Git versions prior to 1.5.1.2 over dumb + transports such as HTTP. This variable determines whether + 'git gc' runs `git pack-refs`. This can be set to "nobare" + to enable it within all non-bare repos or it can be set to a + boolean value. The default is `true`. gc.pruneexpire:: When 'git-gc' is run, it will call 'prune --expire 2.weeks.ago'. @@@ -1145,12 -1136,6 +1149,12 @@@ http.maxRequests: How many HTTP requests to launch in parallel. Can be overridden by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5. +http.minSessions:: + The number of curl sessions (counted across slots) to be kept across + requests. They will not be ended with curl_easy_cleanup() until + http_cleanup() is invoked. If USE_CURL_MULTI is not defined, this + value will be capped at 1. Defaults to 1. + http.postBuffer:: Maximum size in bytes of the buffer used by smart HTTP transports when POSTing data to the remote system. @@@ -1480,10 -1465,6 +1484,10 @@@ remote..tagopt: Setting this value to \--no-tags disables automatic tag following when fetching from remote +remote..vcs:: + Setting this to a value will cause git to interact with + the remote with the git-remote- helper. + remotes.:: The list of remotes which are fetched by "git remote update ". See linkgit:git-remote[1]. diff --combined builtin-commit.c index 9b9dbaa5bf,29dc3df786..42f11c30ca --- a/builtin-commit.c +++ b/builtin-commit.c @@@ -24,7 -24,6 +24,7 @@@ #include "string-list.h" #include "rerere.h" #include "unpack-trees.h" +#include "quote.h" static const char * const builtin_commit_usage[] = { "git commit [options] [--] ...", @@@ -36,7 -35,20 +36,20 @@@ static const char * const builtin_statu NULL }; + static const char implicit_ident_advice[] = + "Your name and email address were configured automatically based\n" + "on your username and hostname. Please check that they are accurate.\n" + "You can suppress this message by setting them explicitly:\n" + "\n" + " git config --global user.name Your Name\n" + " git config --global user.email you@example.com\n" + "\n" + "If the identity used for this commit is wrong, you can fix it with:\n" + "\n" + " git commit --amend --author='Your Name '\n"; + -static unsigned char head_sha1[20], merge_head_sha1[20]; +static unsigned char head_sha1[20]; + static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file index_lock; /* real index */ @@@ -53,7 -65,7 +66,7 @@@ static char *edit_message, *use_message static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; -static char *untracked_files_arg; +static char *untracked_files_arg, *force_date; /* * The default commit message cleanup mode will remove the lines * beginning with # (shell comments) and leading and trailing @@@ -68,17 -80,10 +81,17 @@@ static enum } cleanup_mode; static char *cleanup_arg; -static int use_editor = 1, initial_commit, in_merge; +static int use_editor = 1, initial_commit, in_merge, include_status = 1; static const char *only_include_assumed; static struct strbuf message; +static int null_termination; +static enum { + STATUS_FORMAT_LONG, + STATUS_FORMAT_SHORT, + STATUS_FORMAT_PORCELAIN, +} status_format = STATUS_FORMAT_LONG; + static int opt_parse_m(const struct option *opt, const char *arg, int unset) { struct strbuf *buf = opt->value; @@@ -94,11 -99,10 +107,11 @@@ static struct option builtin_commit_options[] = { OPT__QUIET(&quiet), OPT__VERBOSE(&verbose), - OPT_GROUP("Commit message options"), + OPT_GROUP("Commit message options"), OPT_FILENAME('F', "file", &logfile, "read log from file"), OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"), + OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"), OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m), OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"), OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), @@@ -106,9 -110,6 +119,9 @@@ OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), OPT_FILENAME('t', "template", &template_file, "use specified template file"), OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"), + OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), + OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"), + /* end commit message options */ OPT_GROUP("Commit contents options"), OPT_BOOLEAN('a', "all", &all, "commit all changed files"), @@@ -117,16 -118,10 +130,16 @@@ OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), + OPT_SET_INT(0, "short", &status_format, "show status concisely", + STATUS_FORMAT_SHORT), + OPT_SET_INT(0, "porcelain", &status_format, + "show porcelain output format", STATUS_FORMAT_PORCELAIN), + OPT_BOOLEAN('z', "null", &null_termination, + "terminate entries with NUL"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), - OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), + /* end commit contents options */ OPT_END() }; @@@ -184,15 -179,11 +197,15 @@@ static int list_paths(struct string_lis for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; + struct string_list_item *item; + if (ce->ce_flags & CE_UPDATE) continue; if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m)) continue; - string_list_insert(ce->name, list); + item = string_list_insert(ce->name, list); + if (ce_skip_worktree(ce)) + item->util = item; /* better a valid pointer than a fake one */ } return report_path_error(m, pattern, prefix ? strlen(prefix) : 0); @@@ -205,10 -196,6 +218,10 @@@ static void add_remove_files(struct str struct stat st; struct string_list_item *p = &(list->items[i]); + /* p->util is skip-worktree */ + if (p->util) + continue; + if (!lstat(p->string, &st)) { if (add_to_cache(p->string, &st, 0)) die("updating files failed"); @@@ -332,7 -319,7 +345,7 @@@ static char *prepare_index(int argc, co */ commit_style = COMMIT_PARTIAL; - if (file_exists(git_path("MERGE_HEAD"))) + if (in_merge) die("cannot do a partial commit during a merge."); memset(&partial, 0, sizeof(partial)); @@@ -373,8 -360,6 +386,8 @@@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn, struct wt_status *s) { + unsigned char sha1[20]; + if (s->relative_paths) s->prefix = prefix; @@@ -386,21 -371,8 +399,21 @@@ s->index_file = index_file; s->fp = fp; s->nowarn = nowarn; + s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0; + + wt_status_collect(s); - wt_status_print(s); + switch (status_format) { + case STATUS_FORMAT_SHORT: + wt_shortstatus_print(s, null_termination); + break; + case STATUS_FORMAT_PORCELAIN: + wt_porcelain_print(s, null_termination); + break; + case STATUS_FORMAT_LONG: + wt_status_print(s); + break; + } return s->commitable; } @@@ -451,9 -423,6 +464,9 @@@ static void determine_author_info(void email = xstrndup(lb + 2, rb - (lb + 2)); } + if (force_date) + date = force_date; + author_name = name; author_email = email; author_date = date; @@@ -591,7 -560,7 +604,7 @@@ static int prepare_to_commit(const cha /* This checks if committer ident is explicitly given */ git_committer_info(0); - if (use_editor) { + if (use_editor && include_status) { char *author_ident; const char *committer_ident; @@@ -779,21 -748,6 +792,21 @@@ static const char *find_author_by_nickn die("No existing author found with '%s'", name); } + +static void handle_untracked_files_arg(struct wt_status *s) +{ + if (!untracked_files_arg) + ; /* default already initialized */ + else if (!strcmp(untracked_files_arg, "no")) + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; + else if (!strcmp(untracked_files_arg, "normal")) + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + else if (!strcmp(untracked_files_arg, "all")) + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + else + die("Invalid untracked files mode '%s'", untracked_files_arg); +} + static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix, @@@ -820,6 -774,9 +833,6 @@@ if (get_sha1("HEAD", head_sha1)) initial_commit = 1; - if (!get_sha1("MERGE_HEAD", merge_head_sha1)) - in_merge = 1; - /* Sanity check options */ if (amend && initial_commit) die("You have nothing to amend."); @@@ -899,18 -856,22 +912,18 @@@ else die("Invalid cleanup mode %s", cleanup_arg); - if (!untracked_files_arg) - ; /* default already initialized */ - else if (!strcmp(untracked_files_arg, "no")) - s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; - else if (!strcmp(untracked_files_arg, "normal")) - s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - else if (!strcmp(untracked_files_arg, "all")) - s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; - else - die("Invalid untracked files mode '%s'", untracked_files_arg); + handle_untracked_files_arg(s); if (all && argc > 0) die("Paths with -a does not make sense."); else if (interactive && argc > 0) die("Paths with --interactive does not make sense."); + if (null_termination && status_format == STATUS_FORMAT_LONG) + status_format = STATUS_FORMAT_PORCELAIN; + if (status_format != STATUS_FORMAT_LONG) + dry_run = 1; + return argc; } @@@ -992,72 -953,29 +1005,75 @@@ static int git_status_config(const cha int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; + unsigned char sha1[20]; + static struct option builtin_status_options[] = { + OPT__VERBOSE(&verbose), + OPT_SET_INT('s', "short", &status_format, + "show status concisely", STATUS_FORMAT_SHORT), + OPT_SET_INT(0, "porcelain", &status_format, + "show porcelain output format", + STATUS_FORMAT_PORCELAIN), + OPT_BOOLEAN('z', "null", &null_termination, + "terminate entries with NUL"), + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, + "mode", + "show untracked files, optional modes: all, normal, no. (Default: all)", + PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + OPT_END(), + }; + + if (null_termination && status_format == STATUS_FORMAT_LONG) + status_format = STATUS_FORMAT_PORCELAIN; wt_status_prepare(&s); git_config(git_status_config, &s); + in_merge = file_exists(git_path("MERGE_HEAD")); + argc = parse_options(argc, argv, prefix, + builtin_status_options, + builtin_status_usage, 0); + handle_untracked_files_arg(&s); + + if (*argv) + s.pathspec = get_pathspec(prefix, argv); + + read_cache(); + refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); + s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; + s.in_merge = in_merge; + wt_status_collect(&s); + + if (s.relative_paths) + s.prefix = prefix; if (s.use_color == -1) s.use_color = git_use_color_default; if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_status_usage, - prefix, &s); - return dry_run_commit(argc, argv, prefix, &s); + switch (status_format) { + case STATUS_FORMAT_SHORT: + wt_shortstatus_print(&s, null_termination); + break; + case STATUS_FORMAT_PORCELAIN: + wt_porcelain_print(&s, null_termination); + break; + case STATUS_FORMAT_LONG: + s.verbose = verbose; + wt_status_print(&s); + break; + } + return 0; } static void print_summary(const char *prefix, const unsigned char *sha1) { struct rev_info rev; struct commit *commit; - static const char *format = "format:%h] %s"; + struct strbuf format = STRBUF_INIT; unsigned char junk_sha1[20]; const char *head = resolve_ref("HEAD", junk_sha1, 0, NULL); + struct pretty_print_context pctx = {0}; + struct strbuf author_ident = STRBUF_INIT; + struct strbuf committer_ident = STRBUF_INIT; commit = lookup_commit(sha1); if (!commit) @@@ -1065,6 -983,25 +1081,25 @@@ if (!commit || parse_commit(commit)) die("could not parse newly created commit"); + strbuf_addstr(&format, "format:%h] %s"); + + format_commit_message(commit, "%an <%ae>", &author_ident, &pctx); + format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx); + if (strbuf_cmp(&author_ident, &committer_ident)) { + strbuf_addstr(&format, "\n Author: "); + strbuf_addbuf_percentquote(&format, &author_ident); + } + if (!user_ident_sufficiently_given()) { + strbuf_addstr(&format, "\n Committer: "); + strbuf_addbuf_percentquote(&format, &committer_ident); + if (advice_implicit_identity) { + strbuf_addch(&format, '\n'); + strbuf_addstr(&format, implicit_ident_advice); + } + } + strbuf_release(&author_ident); + strbuf_release(&committer_ident); + init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); @@@ -1075,7 -1012,7 +1110,7 @@@ rev.verbose_header = 1; rev.show_root_diff = 1; - get_commit_format(format, &rev); + get_commit_format(format.buf, &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 100; @@@ -1094,10 -1031,11 +1129,11 @@@ struct pretty_print_context ctx = {0}; struct strbuf buf = STRBUF_INIT; ctx.date_mode = DATE_NORMAL; - format_commit_message(commit, format + 7, &buf, &ctx); + format_commit_message(commit, format.buf + 7, &buf, &ctx); printf("%s\n", buf.buf); strbuf_release(&buf); } + strbuf_release(&format); } static int git_commit_config(const char *k, const char *v, void *cb) @@@ -1106,10 -1044,6 +1142,10 @@@ if (!strcmp(k, "commit.template")) return git_config_pathname(&template_file, k, v); + if (!strcmp(k, "commit.status")) { + include_status = git_config_bool(k, v); + return 0; + } return git_status_config(k, v, s); } @@@ -1128,11 -1062,10 +1164,11 @@@ int cmd_commit(int argc, const char **a wt_status_prepare(&s); git_config(git_commit_config, &s); + in_merge = file_exists(git_path("MERGE_HEAD")); + s.in_merge = in_merge; if (s.use_color == -1) s.use_color = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix, &s); if (dry_run) { @@@ -1255,7 -1188,7 +1291,7 @@@ "new_index file. Check that disk is not full or quota is\n" "not exceeded, and then \"git reset HEAD\" to recover."); - rerere(); + rerere(0); run_hook(get_index_file(), "post-commit", NULL); if (!quiet) print_summary(prefix, commit_sha1); diff --combined daemon.c index 918e560b4e,51d9d6b8ac..360635eb1c --- a/daemon.c +++ b/daemon.c @@@ -147,7 -147,6 +147,6 @@@ static char *path_ok(char *directory { "IP", ip_address }, { "P", tcp_port }, { "D", directory }, - { "%", "%" }, { NULL } }; @@@ -562,24 -561,6 +561,24 @@@ static int execute(struct sockaddr *add return -1; } +static int addrcmp(const struct sockaddr_storage *s1, + const struct sockaddr_storage *s2) +{ + if (s1->ss_family != s2->ss_family) + return s1->ss_family - s2->ss_family; + if (s1->ss_family == AF_INET) + return memcmp(&((struct sockaddr_in *)s1)->sin_addr, + &((struct sockaddr_in *)s2)->sin_addr, + sizeof(struct in_addr)); +#ifndef NO_IPV6 + if (s1->ss_family == AF_INET6) + return memcmp(&((struct sockaddr_in6 *)s1)->sin6_addr, + &((struct sockaddr_in6 *)s2)->sin6_addr, + sizeof(struct in6_addr)); +#endif + return 0; +} + static int max_connections = 32; static unsigned int live_children; @@@ -594,12 -575,17 +593,12 @@@ static void add_child(pid_t pid, struc { struct child *newborn, **cradle; - /* - * This must be xcalloc() -- we'll compare the whole sockaddr_storage - * but individual address may be shorter. - */ newborn = xcalloc(1, sizeof(*newborn)); live_children++; newborn->pid = pid; memcpy(&newborn->address, addr, addrlen); for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next) - if (!memcmp(&(*cradle)->address, &newborn->address, - sizeof(newborn->address))) + if (!addrcmp(&(*cradle)->address, &newborn->address)) break; newborn->next = *cradle; *cradle = newborn; @@@ -632,7 -618,8 +631,7 @@@ static void kill_some_child(void return; for (; (next = blanket->next); blanket = next) - if (!memcmp(&blanket->address, &next->address, - sizeof(next->address))) { + if (!addrcmp(&blanket->address, &next->address)) { kill(blanket->pid, SIGTERM); break; } diff --combined strbuf.c index 3fa81b3365,af9130e52d..67448b7b07 --- a/strbuf.c +++ b/strbuf.c @@@ -91,6 -91,13 +91,6 @@@ void strbuf_ltrim(struct strbuf *sb sb->buf[sb->len] = '\0'; } -void strbuf_tolower(struct strbuf *sb) -{ - int i; - for (i = 0; i < sb->len; i++) - sb->buf[i] = tolower(sb->buf[i]); -} - struct strbuf **strbuf_split(const struct strbuf *sb, int delim) { int alloc = 2, pos = 0; @@@ -220,6 -227,12 +220,12 @@@ void strbuf_expand(struct strbuf *sb, c break; format = percent + 1; + if (*format == '%') { + strbuf_addch(sb, '%'); + format++; + continue; + } + consumed = fn(sb, format, context); if (consumed) format += consumed; @@@ -244,6 -257,17 +250,17 @@@ size_t strbuf_expand_dict_cb(struct str return 0; } + void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src) + { + int i, len = src->len; + + for (i = 0; i < len; i++) { + if (src->buf[i] == '%') + strbuf_addch(dst, '%'); + strbuf_addch(dst, src->buf[i]); + } + } + size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) { size_t res; diff --combined strbuf.h index b37f06a34b,84ac9424b5..8ce2a2e54b --- a/strbuf.h +++ b/strbuf.h @@@ -81,6 -81,7 +81,6 @@@ extern void strbuf_trim(struct strbuf * extern void strbuf_rtrim(struct strbuf *); extern void strbuf_ltrim(struct strbuf *); extern int strbuf_cmp(const struct strbuf *, const struct strbuf *); -extern void strbuf_tolower(struct strbuf *); extern struct strbuf **strbuf_split(const struct strbuf *, int delim); extern void strbuf_list_free(struct strbuf **); @@@ -115,6 -116,7 +115,7 @@@ struct strbuf_expand_dict_entry const char *value; }; extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context); + extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src); __attribute__((format (printf,2,3))) extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); diff --combined t/t7501-commit.sh index a529701241,0166d35e51..7940901d47 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@@ -117,7 -117,11 +117,11 @@@ test_expect_success test_expect_success \ "overriding author from command line" \ "echo 'gak' >file && \ - git commit -m 'author' --author 'Rubber Duck ' -a" + git commit -m 'author' --author 'Rubber Duck ' -a >output 2>&1" + + test_expect_success \ + "commit --author output mentions author" \ + "grep Rubber.Duck output" test_expect_success PERL \ "interactive add" \ @@@ -211,21 -215,6 +215,21 @@@ test_expect_success 'amend commit to fi ' +test_expect_success 'amend commit to fix date' ' + + test_tick && + newtick=$GIT_AUTHOR_DATE && + git reset --hard && + git cat-file -p HEAD | + sed -e "s/author.*/author $author $newtick/" \ + -e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" > \ + expected && + git commit --amend --date="$newtick" && + git cat-file -p HEAD > current && + test_cmp expected current + +' + test_expect_success 'sign off (1)' ' echo 1 >positive &&