diff options
35 files changed, 649 insertions, 207 deletions
diff --git a/Documentation/RelNotes/1.8.5.4.txt b/Documentation/RelNotes/1.8.5.4.txt new file mode 100644 index 0000000000..db3b3d3e3f --- /dev/null +++ b/Documentation/RelNotes/1.8.5.4.txt @@ -0,0 +1,48 @@ +Git v1.8.5.4 Release Notes +========================== + +Fixes since v1.8.5.4 +-------------------- + + * "git fetch --depth=0" was a no-op, and was silently ignored. + Diagnose it as an error. + + * Remote repository URL expressed in scp-style host:path notation are + parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks + to connect to user's home directory on host at address ::1. + + * SSL-related options were not passed correctly to underlying socket + layer in "git send-email". + + * "git commit -v" appends the patch to the log message before + editing, and then removes the patch when the editor returned + control. However, the patch was not stripped correctly when the + first modified path was a submodule. + + * "git mv A B/", when B does not exist as a directory, should error + out, but it didn't. + + * When we figure out how many file descriptors to allocate for + keeping packfiles open, a system with non-working getrlimit() could + cause us to die(), but because we make this call only to get a + rough estimate of how many is available and we do not even attempt + to use up all file descriptors available ourselves, it is nicer to + fall back to a reasonable low value rather than dying. + + * "git log --decorate" did not handle a tag pointed by another tag + nicely. + + * "git add -A" (no other arguments) in a totally empty working tree + used to emit an error. + + * There is no reason to have a hardcoded upper limit of the number of + parents for an octopus merge, created via the graft mechanism, but + there was. + + * The implementation of 'git stash $cmd "stash@{...}"' did not quote + the stash argument properly and left it split at IFS whitespace. + + * The documentation to "git pull" hinted there is an "-m" option + because it incorrectly shared the documentation with "git merge". + +Also contains typofixes, documentation updates and trivial code clean-ups. diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 6083aab87b..200eb22260 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -99,10 +99,10 @@ must be given before the options meant for 'git fetch'. Options related to merging ~~~~~~~~~~~~~~~~~~~~~~~~~~ -include::merge-options.txt[] - :git-pull: 1 +include::merge-options.txt[] + -r:: --rebase[=false|true|preserve]:: When true, rebase the current branch on top of the upstream diff --git a/Documentation/git.txt b/Documentation/git.txt index 388b19633e..36483181cb 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.8.5.3/git.html[documentation for release 1.8.5.3] +* link:v1.8.5.4/git.html[documentation for release 1.8.5.4] * release notes for + link:RelNotes/1.8.5.4.txt[1.8.5.4], link:RelNotes/1.8.5.3.txt[1.8.5.3], link:RelNotes/1.8.5.2.txt[1.8.5.2], link:RelNotes/1.8.5.1.txt[1.8.5.1], diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index afba8d4f3b..e1343155fa 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -14,9 +14,12 @@ inspect and further tweak the merge result before committing. further edit the auto-generated merge message, so that the user can explain and justify the merge. The `--no-edit` option can be used to accept the auto-generated message (this is generally - discouraged). The `--edit` (or `-e`) option is still useful if you are - giving a draft message with the `-m` option from the command line - and want to edit it in the editor. + discouraged). +ifndef::git-pull[] +The `--edit` (or `-e`) option is still useful if you are +giving a draft message with the `-m` option from the command line +and want to edit it in the editor. +endif::git-pull[] + Older scripts may depend on the historical behaviour of not allowing the user to edit the merge log message. They will see an editor opened when diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index a8f58ee282..ccec5effb1 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.8.5.3 +DEF_VER=v1.8.5.4 LF=' ' @@ -1 +1 @@ -Documentation/RelNotes/1.8.5.3.txt
\ No newline at end of file +Documentation/RelNotes/1.8.5.4.txt
\ No newline at end of file diff --git a/builtin/add.c b/builtin/add.c index 226f758869..d7e3e44d06 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -544,7 +544,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) for (i = 0; i < pathspec.nr; i++) { const char *path = pathspec.items[i].match; - if (!seen[i] && + if (!seen[i] && path[0] && ((pathspec.items[i].magic & (PATHSPEC_GLOB | PATHSPEC_ICASE)) || !file_exists(path))) { diff --git a/builtin/blame.c b/builtin/blame.c index 1407ae7eb2..9047b6ef4c 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1804,17 +1804,17 @@ static int prepare_lines(struct scoreboard *sb) static int read_ancestry(const char *graft_file) { FILE *fp = fopen(graft_file, "r"); - char buf[1024]; + struct strbuf buf = STRBUF_INIT; if (!fp) return -1; - while (fgets(buf, sizeof(buf), fp)) { + while (!strbuf_getwholeline(&buf, fp, '\n')) { /* The format is just "Commit Parent1 Parent2 ...\n" */ - int len = strlen(buf); - struct commit_graft *graft = read_graft_line(buf, len); + struct commit_graft *graft = read_graft_line(buf.buf, buf.len); if (graft) register_commit_graft(graft, 0); } fclose(fp); + strbuf_release(&buf); return 0; } diff --git a/builtin/clone.c b/builtin/clone.c index 874e0fd0b6..cc11104d42 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -796,6 +796,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_local > 0 && !is_local) warning(_("--local is ignored")); + /* no need to be strict, transport_set_option() will validate it again */ + if (option_depth && atoi(option_depth) < 1) + die(_("depth %s is not a positive number"), option_depth); + if (argc == 2) dir = xstrdup(argv[1]); else diff --git a/builtin/commit.c b/builtin/commit.c index 6ab4605cf5..fedb45af8c 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1505,7 +1505,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct strbuf sb = STRBUF_INIT; struct strbuf author_ident = STRBUF_INIT; const char *index_file, *reflog_msg; - char *nl, *p; + char *nl; unsigned char sha1[20]; struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; @@ -1601,11 +1601,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } /* Truncate the message just before the diff, if any. */ - if (verbose) { - p = strstr(sb.buf, "\ndiff --git "); - if (p != NULL) - strbuf_setlen(&sb, p - sb.buf + 1); - } + if (verbose) + wt_status_truncate_message_at_cut_line(&sb); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, cleanup_mode == CLEANUP_ALL); diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index c8e858232a..758b5acd55 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -7,7 +7,7 @@ static const char fetch_pack_usage[] = "git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] " "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] " -"[--no-progress] [-v] [<host>:]<directory> [<refs>...]"; +"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]"; static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc, const char *name, int namelen) @@ -81,6 +81,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) args.stdin_refs = 1; continue; } + if (!strcmp("--diag-url", arg)) { + args.diag_url = 1; + continue; + } if (!strcmp("-v", arg)) { args.verbose = 1; continue; @@ -146,10 +150,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) fd[0] = 0; fd[1] = 1; } else { + int flags = args.verbose ? CONNECT_VERBOSE : 0; + if (args.diag_url) + flags |= CONNECT_DIAG_URL; conn = git_connect(fd, dest, args.uploadpack, - args.verbose ? CONNECT_VERBOSE : 0); + flags); + if (!conn) + return args.diag_url ? 0 : 1; } - get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL); ref = fetch_pack(&args, fd, conn, ref, dest, diff --git a/builtin/fetch.c b/builtin/fetch.c index bd7a10164f..5bd00d064a 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1075,6 +1075,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } } + /* no need to be strict, transport_set_option() will validate it again */ + if (depth && atoi(depth) < 1) + die(_("depth %s is not a positive number"), depth); + if (recurse_submodules != RECURSE_SUBMODULES_OFF) { if (recurse_submodules_default) { int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); diff --git a/builtin/repack.c b/builtin/repack.c index 91e2363c71..a2b9dba522 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -129,10 +129,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix) /* variables to be filled by option parsing */ int pack_everything = 0; int delete_redundant = 0; - char *unpack_unreachable = NULL; - int window = 0, window_memory = 0; - int depth = 0; - int max_pack_size = 0; + const char *unpack_unreachable = NULL; + const char *window = NULL, *window_memory = NULL; + const char *depth = NULL; + const char *max_pack_size = NULL; int no_reuse_delta = 0, no_reuse_object = 0; int no_update_server_info = 0; int quiet = 0; @@ -157,13 +157,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix) N_("pass --local to git-pack-objects")), OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"), N_("with -A, do not loosen objects older than this")), - OPT_INTEGER(0, "window", &window, + OPT_STRING(0, "window", &window, N_("n"), N_("size of the window used for delta compression")), - OPT_INTEGER(0, "window-memory", &window_memory, + OPT_STRING(0, "window-memory", &window_memory, N_("bytes"), N_("same as the above, but limit memory size instead of entries count")), - OPT_INTEGER(0, "depth", &depth, + OPT_STRING(0, "depth", &depth, N_("n"), N_("limits the maximum delta depth")), - OPT_INTEGER(0, "max-pack-size", &max_pack_size, + OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"), N_("maximum size of each packfile")), OPT_END() }; @@ -185,13 +185,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix) argv_array_push(&cmd_args, "--all"); argv_array_push(&cmd_args, "--reflog"); if (window) - argv_array_pushf(&cmd_args, "--window=%u", window); + argv_array_pushf(&cmd_args, "--window=%s", window); if (window_memory) - argv_array_pushf(&cmd_args, "--window-memory=%u", window_memory); + argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory); if (depth) - argv_array_pushf(&cmd_args, "--depth=%u", depth); + argv_array_pushf(&cmd_args, "--depth=%s", depth); if (max_pack_size) - argv_array_pushf(&cmd_args, "--max_pack_size=%u", max_pack_size); + argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size); if (no_reuse_delta) argv_array_pushf(&cmd_args, "--no-reuse-delta"); if (no_reuse_object) @@ -196,19 +196,19 @@ bad_graft_data: static int read_graft_file(const char *graft_file) { FILE *fp = fopen(graft_file, "r"); - char buf[1024]; + struct strbuf buf = STRBUF_INIT; if (!fp) return -1; - while (fgets(buf, sizeof(buf), fp)) { + while (!strbuf_getwholeline(&buf, fp, '\n')) { /* The format is just "Commit Parent1 Parent2 ...\n" */ - int len = strlen(buf); - struct commit_graft *graft = read_graft_line(buf, len); + struct commit_graft *graft = read_graft_line(buf.buf, buf.len); if (!graft) continue; if (register_commit_graft(graft, 1)) - error("duplicate graft data: %s", buf); + error("duplicate graft data: %s", buf.buf); } fclose(fp); + strbuf_release(&buf); return 0; } @@ -232,10 +232,34 @@ int server_supports(const char *feature) enum protocol { PROTO_LOCAL = 1, + PROTO_FILE, PROTO_SSH, PROTO_GIT }; +int url_is_local_not_ssh(const char *url) +{ + const char *colon = strchr(url, ':'); + const char *slash = strchr(url, '/'); + return !colon || (slash && slash < colon) || + has_dos_drive_prefix(url); +} + +static const char *prot_name(enum protocol protocol) +{ + switch (protocol) { + case PROTO_LOCAL: + case PROTO_FILE: + return "file"; + case PROTO_SSH: + return "ssh"; + case PROTO_GIT: + return "git"; + default: + return "unkown protocol"; + } +} + static enum protocol get_protocol(const char *name) { if (!strcmp(name, "ssh")) @@ -247,7 +271,7 @@ static enum protocol get_protocol(const char *name) if (!strcmp(name, "ssh+git")) return PROTO_SSH; if (!strcmp(name, "file")) - return PROTO_LOCAL; + return PROTO_FILE; die("I don't handle protocol '%s'", name); } @@ -527,55 +551,31 @@ static struct child_process *git_proxy_connect(int fd[2], char *host) return proxy; } -#define MAX_CMD_LEN 1024 - -static char *get_port(char *host) +static const char *get_port_numeric(const char *p) { char *end; - char *p = strchr(host, ':'); - if (p) { long port = strtol(p + 1, &end, 10); if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) { - *p = '\0'; - return p+1; + return p; } } return NULL; } -static struct child_process no_fork; - /* - * This returns a dummy child_process if the transport protocol does not - * need fork(2), or a struct child_process object if it does. Once done, - * finish the connection with finish_connect() with the value returned from - * this function (it is safe to call finish_connect() with NULL to support - * the former case). - * - * If it returns, the connect is successful; it just dies on errors (this - * will hopefully be changed in a libification effort, to return NULL when - * the connection failed). + * Extract protocol and relevant parts from the specified connection URL. + * The caller must free() the returned strings. */ -struct child_process *git_connect(int fd[2], const char *url_orig, - const char *prog, int flags) +static enum protocol parse_connect_url(const char *url_orig, char **ret_host, + char **ret_path) { char *url; char *host, *path; char *end; - int c; - struct child_process *conn = &no_fork; + int separator = '/'; enum protocol protocol = PROTO_LOCAL; - int free_path = 0; - char *port = NULL; - const char **arg; - struct strbuf cmd; - - /* Without this we cannot rely on waitpid() to tell - * what happened to our children. - */ - signal(SIGCHLD, SIG_DFL); if (is_url(url_orig)) url = url_decode(url_orig); @@ -587,40 +587,33 @@ struct child_process *git_connect(int fd[2], const char *url_orig, *host = '\0'; protocol = get_protocol(url); host += 3; - c = '/'; } else { host = url; - c = ':'; + if (!url_is_local_not_ssh(url)) { + protocol = PROTO_SSH; + separator = ':'; + } } /* - * Don't do destructive transforms with git:// as that - * protocol code does '[]' unwrapping of its own. + * Don't do destructive transforms as protocol code does + * '[]' unwrapping in get_host_and_port() */ if (host[0] == '[') { end = strchr(host + 1, ']'); if (end) { - if (protocol != PROTO_GIT) { - *end = 0; - host++; - } end++; } else end = host; } else end = host; - path = strchr(end, c); - if (path && !has_dos_drive_prefix(end)) { - if (c == ':') { - if (host != url || path < strchrnul(host, '/')) { - protocol = PROTO_SSH; - *path++ = '\0'; - } else /* '/' in the host part, assume local path */ - path = end; - } - } else + if (protocol == PROTO_LOCAL) path = end; + else if (protocol == PROTO_FILE && has_dos_drive_prefix(end)) + path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */ + else + path = strchr(end, separator); if (!path || !*path) die("No path specified. See 'man git-pull' for valid url syntax"); @@ -629,33 +622,67 @@ struct child_process *git_connect(int fd[2], const char *url_orig, * null-terminate hostname and point path to ~ for URL's like this: * ssh://host.xz/~user/repo */ - if (protocol != PROTO_LOCAL && host != url) { - char *ptr = path; + + end = path; /* Need to \0 terminate host here */ + if (separator == ':') + path++; /* path starts after ':' */ + if (protocol == PROTO_GIT || protocol == PROTO_SSH) { if (path[1] == '~') path++; - else { - path = xstrdup(ptr); - free_path = 1; - } - - *ptr = '\0'; } - /* - * Add support for ssh port: ssh://host.xy:<port>/... + path = xstrdup(path); + *end = '\0'; + + *ret_host = xstrdup(host); + *ret_path = path; + free(url); + return protocol; +} + +static struct child_process no_fork; + +/* + * This returns a dummy child_process if the transport protocol does not + * need fork(2), or a struct child_process object if it does. Once done, + * finish the connection with finish_connect() with the value returned from + * this function (it is safe to call finish_connect() with NULL to support + * the former case). + * + * If it returns, the connect is successful; it just dies on errors (this + * will hopefully be changed in a libification effort, to return NULL when + * the connection failed). + */ +struct child_process *git_connect(int fd[2], const char *url, + const char *prog, int flags) +{ + char *hostandport, *path; + struct child_process *conn = &no_fork; + enum protocol protocol; + const char **arg; + struct strbuf cmd = STRBUF_INIT; + + /* Without this we cannot rely on waitpid() to tell + * what happened to our children. */ - if (protocol == PROTO_SSH && host != url) - port = get_port(end); + signal(SIGCHLD, SIG_DFL); - if (protocol == PROTO_GIT) { + protocol = parse_connect_url(url, &hostandport, &path); + if (flags & CONNECT_DIAG_URL) { + printf("Diag: url=%s\n", url ? url : "NULL"); + printf("Diag: protocol=%s\n", prot_name(protocol)); + printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL"); + printf("Diag: path=%s\n", path ? path : "NULL"); + conn = NULL; + } else if (protocol == PROTO_GIT) { /* These underlying connection commands die() if they * cannot connect. */ - char *target_host = xstrdup(host); - if (git_use_proxy(host)) - conn = git_proxy_connect(fd, host); + char *target_host = xstrdup(hostandport); + if (git_use_proxy(hostandport)) + conn = git_proxy_connect(fd, hostandport); else - git_tcp_connect(fd, host, flags); + git_tcp_connect(fd, hostandport, flags); /* * Separate original protocol components prog and path * from extended host header with a NUL byte. @@ -668,55 +695,51 @@ struct child_process *git_connect(int fd[2], const char *url_orig, prog, path, 0, target_host, 0); free(target_host); - free(url); - if (free_path) - free(path); - return conn; - } - - conn = xcalloc(1, sizeof(*conn)); - - strbuf_init(&cmd, MAX_CMD_LEN); - strbuf_addstr(&cmd, prog); - strbuf_addch(&cmd, ' '); - sq_quote_buf(&cmd, path); - if (cmd.len >= MAX_CMD_LEN) - die("command line too long"); - - conn->in = conn->out = -1; - conn->argv = arg = xcalloc(7, sizeof(*arg)); - if (protocol == PROTO_SSH) { - const char *ssh = getenv("GIT_SSH"); - int putty = ssh && strcasestr(ssh, "plink"); - if (!ssh) ssh = "ssh"; - - *arg++ = ssh; - if (putty && !strcasestr(ssh, "tortoiseplink")) - *arg++ = "-batch"; - if (port) { - /* P is for PuTTY, p is for OpenSSH */ - *arg++ = putty ? "-P" : "-p"; - *arg++ = port; + } else { + conn = xcalloc(1, sizeof(*conn)); + + strbuf_addstr(&cmd, prog); + strbuf_addch(&cmd, ' '); + sq_quote_buf(&cmd, path); + + conn->in = conn->out = -1; + conn->argv = arg = xcalloc(7, sizeof(*arg)); + if (protocol == PROTO_SSH) { + const char *ssh = getenv("GIT_SSH"); + int putty = ssh && strcasestr(ssh, "plink"); + char *ssh_host = hostandport; + const char *port = NULL; + get_host_and_port(&ssh_host, &port); + port = get_port_numeric(port); + + if (!ssh) ssh = "ssh"; + + *arg++ = ssh; + if (putty && !strcasestr(ssh, "tortoiseplink")) + *arg++ = "-batch"; + if (port) { + /* P is for PuTTY, p is for OpenSSH */ + *arg++ = putty ? "-P" : "-p"; + *arg++ = port; + } + *arg++ = ssh_host; + } else { + /* remove repo-local variables from the environment */ + conn->env = local_repo_env; + conn->use_shell = 1; } - *arg++ = host; - } - else { - /* remove repo-local variables from the environment */ - conn->env = local_repo_env; - conn->use_shell = 1; - } - *arg++ = cmd.buf; - *arg = NULL; + *arg++ = cmd.buf; + *arg = NULL; - if (start_command(conn)) - die("unable to fork"); + if (start_command(conn)) + die("unable to fork"); - fd[0] = conn->out; /* read from child's stdout */ - fd[1] = conn->in; /* write to child's stdin */ - strbuf_release(&cmd); - free(url); - if (free_path) - free(path); + fd[0] = conn->out; /* read from child's stdout */ + fd[1] = conn->in; /* write to child's stdin */ + strbuf_release(&cmd); + } + free(hostandport); + free(path); return conn; } @@ -2,11 +2,13 @@ #define CONNECT_H #define CONNECT_VERBOSE (1u << 0) +#define CONNECT_DIAG_URL (1u << 1) extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); extern int finish_connect(struct child_process *conn); extern int git_connection_is_socket(struct child_process *conn); extern int server_supports(const char *feature); extern int parse_feature_request(const char *features, const char *feature); extern const char *server_feature_value(const char *feature, int *len_ret); +extern int url_is_local_not_ssh(const char *url); #endif diff --git a/fetch-pack.h b/fetch-pack.h index 461cbf39b2..20ccc12e57 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -14,6 +14,7 @@ struct fetch_pack_args { use_thin_pack:1, fetch_all:1, stdin_refs:1, + diag_url:1, verbose:1, no_progress:1, include_tag:1, diff --git a/git-send-email.perl b/git-send-email.perl index 3782c3b0cb..fdb0029b59 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -291,7 +291,7 @@ my $rc = GetOptions("h" => \$help, "smtp-pass:s" => \$smtp_authpass, "smtp-ssl" => sub { $smtp_encryption = 'ssl' }, "smtp-encryption=s" => \$smtp_encryption, - "smtp-ssl-cert-path" => \$smtp_ssl_cert_path, + "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path, "smtp-debug:i" => \$debug_net_smtp, "smtp-domain:s" => \$smtp_domain, "identity=s" => \$identity, @@ -1095,7 +1095,8 @@ sub ssl_verify_params { } if (!defined $smtp_ssl_cert_path) { - $smtp_ssl_cert_path = "/etc/ssl/certs"; + # use the OpenSSL defaults + return (SSL_verify_mode => SSL_VERIFY_PEER()); } if ($smtp_ssl_cert_path eq "") { @@ -1214,10 +1215,14 @@ X-Mailer: git-send-email $gitversion $smtp_server_port ||= 465; # ssmtp require Net::SMTP::SSL; $smtp_domain ||= maildomain(); + require IO::Socket::SSL; + # Net::SMTP::SSL->new() does not forward any SSL options + IO::Socket::SSL::set_client_defaults( + ssl_verify_params()); $smtp ||= Net::SMTP::SSL->new($smtp_server, Hello => $smtp_domain, Port => $smtp_server_port, - ssl_verify_params()); + Debug => $debug_net_smtp); } else { require Net::SMTP; diff --git a/git-stash.sh b/git-stash.sh index 1e541a2125..f0a94abf14 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -358,7 +358,7 @@ parse_flags_and_rev() i_tree= u_tree= - REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1 + REV=$(git rev-parse --no-flags --symbolic --sq "$@") || exit 1 FLAGS= for opt @@ -376,7 +376,7 @@ parse_flags_and_rev() esac done - set -- $REV + eval set -- $REV case $# in 0) @@ -391,13 +391,13 @@ parse_flags_and_rev() ;; esac - REV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null) || { + REV=$(git rev-parse --quiet --symbolic --verify "$1" 2>/dev/null) || { reference="$1" die "$(eval_gettext "\$reference is not valid reference")" } - i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null) && - set -- $(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null) && + i_commit=$(git rev-parse --quiet --verify "$REV^2" 2>/dev/null) && + set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) && s=$1 && w_commit=$1 && b_commit=$2 && @@ -408,8 +408,8 @@ parse_flags_and_rev() test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && IS_STASH_REF=t - u_commit=$(git rev-parse --quiet --verify $REV^3 2>/dev/null) && - u_tree=$(git rev-parse $REV^3: 2>/dev/null) + u_commit=$(git rev-parse --quiet --verify "$REV^3" 2>/dev/null) && + u_tree=$(git rev-parse "$REV^3:" 2>/dev/null) } is_stash_like() diff --git a/log-tree.c b/log-tree.c index 8534d91826..1982631ca4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -134,6 +134,8 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in obj = ((struct tag *)obj)->tagged; if (!obj) break; + if (!obj->parsed) + parse_object(obj->sha1); add_name_decoration(DECORATION_REF_TAG, refname, obj); } return 0; diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm index b3bcd476da..34e8af966c 100644 --- a/perl/Git/SVN/Editor.pm +++ b/perl/Git/SVN/Editor.pm @@ -304,8 +304,12 @@ sub C { my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); my $pbat = $self->ensure_path($dir, $deletions); + # workaround for a bug in svn serf backend (v1.8.5 and below): + # store third argument to ->add_file() in a local variable, to make it + # have the same lifetime as $fbat + my $upa = $self->url_path($m->{file_a}); my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, - $self->url_path($m->{file_a}), $self->{r}); + $upa, $self->{r}); print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q; $self->chg_file($fbat, $m); $self->close_file($fbat,undef,$self->{pool}); @@ -323,8 +327,10 @@ sub R { my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); my $pbat = $self->ensure_path($dir, $deletions); + # workaround for a bug in svn serf backend, see comment in C() above + my $upa = $self->url_path($m->{file_a}); my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, - $self->url_path($m->{file_a}), $self->{r}); + $upa, $self->{r}); print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q; $self->apply_autoprops($file, $fbat); $self->chg_file($fbat, $m); diff --git a/sha1_file.c b/sha1_file.c index 760dd60031..06c809aeeb 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -807,15 +807,38 @@ void free_pack_by_name(const char *pack_name) static unsigned int get_max_fd_limit(void) { #ifdef RLIMIT_NOFILE - struct rlimit lim; + { + struct rlimit lim; - if (getrlimit(RLIMIT_NOFILE, &lim)) - die_errno("cannot get RLIMIT_NOFILE"); + if (!getrlimit(RLIMIT_NOFILE, &lim)) + return lim.rlim_cur; + } +#endif + +#ifdef _SC_OPEN_MAX + { + long open_max = sysconf(_SC_OPEN_MAX); + if (0 < open_max) + return open_max; + /* + * Otherwise, we got -1 for one of the two + * reasons: + * + * (1) sysconf() did not understand _SC_OPEN_MAX + * and signaled an error with -1; or + * (2) sysconf() said there is no limit. + * + * We _could_ clear errno before calling sysconf() to + * tell these two cases apart and return a huge number + * in the latter case to let the caller cap it to a + * value that is not so selfish, but letting the + * fallback OPEN_MAX codepath take care of these cases + * is a lot simpler. + */ + } +#endif - return lim.rlim_cur; -#elif defined(_SC_OPEN_MAX) - return sysconf(_SC_OPEN_MAX); -#elif defined(OPEN_MAX) +#ifdef OPEN_MAX return OPEN_MAX; #else return 1; /* see the caller ;-) */ diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index c9d105d707..304c7b7d87 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -116,6 +116,27 @@ test_expect_success 'blame evil merge' ' check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 ' +test_expect_success 'blame huge graft' ' + test_when_finished "git checkout branch2" && + test_when_finished "rm -f .git/info/grafts" && + graft= && + for i in 0 1 2 + do + for j in 0 1 2 3 4 5 6 7 8 9 + do + git checkout --orphan "$i$j" && + printf "%s\n" "$i" "$j" >file && + test_tick && + GIT_AUTHOR_NAME=$i$j GIT_AUTHOR_EMAIL=$i$j@test.git \ + git commit -a -m "$i$j" && + commit=$(git rev-parse --verify HEAD) && + graft="$graft$commit " + done + done && + printf "%s " $graft >.git/info/grafts && + check_count -h 00 01 1 10 1 +' + test_expect_success 'setup incomplete line' ' echo "incomplete" | tr -d "\\012" >>file && GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" \ diff --git a/t/t3700-add.sh b/t/t3700-add.sh index aab86e838b..fe274e2fb1 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -272,6 +272,25 @@ test_expect_success '"add non-existent" should fail' ' ! (git ls-files | grep "non-existent") ' +test_expect_success 'git add -A on empty repo does not error out' ' + rm -fr empty && + git init empty && + ( + cd empty && + git add -A . && + git add -A + ) +' + +test_expect_success '"git add ." in empty repo' ' + rm -fr empty && + git init empty && + ( + cd empty && + git add . + ) +' + test_expect_success 'git add --dry-run of existing changed file' " echo new >>track-this && git add --dry-run track-this >actual 2>&1 && diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index debda7a678..5b79b216e2 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -673,4 +673,16 @@ test_expect_success 'store updates stash ref and reflog' ' grep quux bazzy ' +test_expect_success 'handle stash specification with spaces' ' + git stash clear && + echo pig >file && + git stash && + stamp=$(git log -g --format="%cd" -1 refs/stash) && + test_tick && + echo cow >file && + git stash && + git stash apply "stash@{$stamp}" && + grep pig file +' + test_done diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index af5134b70c..589bc6bfb4 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -110,4 +110,17 @@ test_expect_success 'diff-tree -r with wildcard' ' test_cmp expected result ' +test_expect_success 'diff multiple wildcard pathspecs' ' + mkdir path2 && + echo rezrov >path2/file1 && + git update-index --add path2/file1 && + tree3=`git write-tree` && + git diff --name-only $tree $tree3 -- "path2*1" "path1*1" >actual && + cat <<-\EOF >expect && + path1/file1 + path2/file1 + EOF + test_cmp expect actual +' + test_done diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index fb00041139..2a6278bb33 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -310,4 +310,19 @@ EOF test_cmp expected actual ' +test_expect_success 'log decoration properly follows tag chain' ' + git tag -a tag1 -m tag1 && + git tag -a tag2 -m tag2 tag1 && + git tag -d tag1 && + git commit --amend -m shorter && + git log --no-walk --tags --pretty="%H %d" --decorate=full >actual && + cat <<EOF >expected && +6a908c10688b2503073c39c9ba26322c73902bb5 (tag: refs/tags/tag2) +9f716384d92283fb915a4eee5073f030638e05f9 (tag: refs/tags/message-one) +b87e4cccdb77336ea79d89224737be7ea8e95367 (tag: refs/tags/message-two) +EOF + sort actual >actual1 && + test_cmp expected actual1 +' + test_done diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index d87ddf73b7..5b2b1c2c13 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -531,5 +531,92 @@ test_expect_success 'shallow fetch with tags does not break the repository' ' git fsck ) ' +check_prot_path () { + cat >expected <<-EOF && + Diag: url=$1 + Diag: protocol=$2 + Diag: path=$3 + EOF + git fetch-pack --diag-url "$1" | grep -v hostandport= >actual && + test_cmp expected actual +} + +check_prot_host_path () { + cat >expected <<-EOF && + Diag: url=$1 + Diag: protocol=$2 + Diag: hostandport=$3 + Diag: path=$4 + EOF + git fetch-pack --diag-url "$1" >actual && + test_cmp expected actual +} + +for r in repo re:po re/po +do + # git or ssh with scheme + for p in "ssh+git" "git+ssh" git ssh + do + for h in host host:12 [::1] [::1]:23 + do + case "$p" in + *ssh*) + pp=ssh + ;; + *) + pp=$p + ;; + esac + test_expect_success "fetch-pack --diag-url $p://$h/$r" ' + check_prot_host_path $p://$h/$r $pp "$h" "/$r" + ' + # "/~" -> "~" conversion + test_expect_success "fetch-pack --diag-url $p://$h/~$r" ' + check_prot_host_path $p://$h/~$r $pp "$h" "~$r" + ' + done + done + # file with scheme + for p in file + do + test_expect_success "fetch-pack --diag-url $p://$h/$r" ' + check_prot_path $p://$h/$r $p "/$r" + ' + # No "/~" -> "~" conversion for file + test_expect_success "fetch-pack --diag-url $p://$h/~$r" ' + check_prot_path $p://$h/~$r $p "/~$r" + ' + done + # file without scheme + for h in nohost nohost:12 [::1] [::1]:23 [ [:aa + do + test_expect_success "fetch-pack --diag-url ./$h:$r" ' + check_prot_path ./$h:$r $p "./$h:$r" + ' + # No "/~" -> "~" conversion for file + test_expect_success "fetch-pack --diag-url ./$p:$h/~$r" ' + check_prot_path ./$p:$h/~$r $p "./$p:$h/~$r" + ' + done + #ssh without scheme + p=ssh + for h in host [::1] + do + test_expect_success "fetch-pack --diag-url $h:$r" ' + check_prot_path $h:$r $p "$r" + ' + # Do "/~" -> "~" conversion + test_expect_success "fetch-pack --diag-url $h:/~$r" ' + check_prot_host_path $h:/~$r $p "$h" "~$r" + ' + done +done + +test_expect_success MINGW 'fetch-pack --diag-url file://c:/repo' ' + check_prot_path file://c:/repo file c:/repo +' +test_expect_success MINGW 'fetch-pack --diag-url c:repo' ' + check_prot_path c:repo file c:repo +' test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 1d1c8755ea..62fbd7e664 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -280,25 +280,26 @@ test_expect_success 'clone checking out a tag' ' test_cmp fetch.expected fetch.actual ' -test_expect_success 'setup ssh wrapper' ' - write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF && - echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" && - # throw away all but the last argument, which should be the - # command - while test $# -gt 1; do shift; done - eval "$1" - EOF - - GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" && - export GIT_SSH && - export TRASH_DIRECTORY -' - -clear_ssh () { - >"$TRASH_DIRECTORY/ssh-output" +setup_ssh_wrapper () { + test_expect_success 'setup ssh wrapper' ' + write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF && + echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" && + # throw away all but the last argument, which should be the + # command + while test $# -gt 1; do shift; done + eval "$1" + EOF + GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" && + export GIT_SSH && + export TRASH_DIRECTORY && + >"$TRASH_DIRECTORY"/ssh-output + ' } expect_ssh () { + test_when_finished ' + (cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output) + ' && { case "$1" in none) @@ -310,25 +311,114 @@ expect_ssh () { (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output) } -test_expect_success 'cloning myhost:src uses ssh' ' - clear_ssh && +setup_ssh_wrapper + +test_expect_success 'clone myhost:src uses ssh' ' git clone myhost:src ssh-clone && expect_ssh myhost src ' test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' ' - clear_ssh && cp -R src "foo:bar" && - git clone "./foo:bar" foobar && + git clone "foo:bar" foobar && expect_ssh none ' test_expect_success 'bracketed hostnames are still ssh' ' - clear_ssh && git clone "[myhost:123]:src" ssh-bracket-clone && expect_ssh myhost:123 src ' +counter=0 +# $1 url +# $2 none|host +# $3 path +test_clone_url () { + counter=$(($counter + 1)) + test_might_fail git clone "$1" tmp$counter && + expect_ssh "$2" "$3" +} + +test_expect_success NOT_MINGW 'clone c:temp is ssl' ' + test_clone_url c:temp c temp +' + +test_expect_success MINGW 'clone c:temp is dos drive' ' + test_clone_url c:temp none +' + +#ip v4 +for repo in rep rep/home/project 123 +do + test_expect_success "clone host:$repo" ' + test_clone_url host:$repo host $repo + ' +done + +#ipv6 +for repo in rep rep/home/project 123 +do + test_expect_success "clone [::1]:$repo" ' + test_clone_url [::1]:$repo ::1 $repo + ' +done +#home directory +test_expect_success "clone host:/~repo" ' + test_clone_url host:/~repo host "~repo" +' + +test_expect_success "clone [::1]:/~repo" ' + test_clone_url [::1]:/~repo ::1 "~repo" +' + +# Corner cases +for url in foo/bar:baz [foo]bar/baz:qux [foo/bar]:baz +do + test_expect_success "clone $url is not ssh" ' + test_clone_url $url none + ' +done + +#with ssh:// scheme +test_expect_success 'clone ssh://host.xz/home/user/repo' ' + test_clone_url "ssh://host.xz/home/user/repo" host.xz "/home/user/repo" +' + +# from home directory +test_expect_success 'clone ssh://host.xz/~repo' ' + test_clone_url "ssh://host.xz/~repo" host.xz "~repo" +' + +# with port number +test_expect_success 'clone ssh://host.xz:22/home/user/repo' ' + test_clone_url "ssh://host.xz:22/home/user/repo" "-p 22 host.xz" "/home/user/repo" +' + +# from home directory with port number +test_expect_success 'clone ssh://host.xz:22/~repo' ' + test_clone_url "ssh://host.xz:22/~repo" "-p 22 host.xz" "~repo" +' + +#IPv6 +test_expect_success 'clone ssh://[::1]/home/user/repo' ' + test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo" +' + +#IPv6 from home directory +test_expect_success 'clone ssh://[::1]/~repo' ' + test_clone_url "ssh://[::1]/~repo" "::1" "~repo" +' + +#IPv6 with port number +test_expect_success 'clone ssh://[::1]:22/home/user/repo' ' + test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" "/home/user/repo" +' + +#IPv6 from home directory with port number +test_expect_success 'clone ssh://[::1]:22/~repo' ' + test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo" +' + test_expect_success 'clone from a repository with two identical branches' ' ( diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh index 7ea14ced31..10b1452766 100755 --- a/t/t6101-rev-parse-parents.sh +++ b/t/t6101-rev-parse-parents.sh @@ -20,7 +20,17 @@ test_expect_success 'setup' ' test_commit start2 && git checkout master && git merge -m next start2 && - test_commit final + test_commit final && + + test_seq 40 | + while read i + do + git checkout --orphan "b$i" && + test_tick && + git commit --allow-empty -m "$i" && + commit=$(git rev-parse --verify HEAD) && + printf "$commit " >>.git/info/grafts + done ' test_expect_success 'start is valid' ' @@ -79,6 +89,10 @@ test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' ' test_cmp expect actual ' +test_expect_success 'large graft octopus' ' + test_cmp_rev_output b31 "git rev-parse --verify b1^30" +' + test_expect_success 'repack for next test' ' git repack -a -d ' diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh index da5bd3b5a5..2ddf28c984 100755 --- a/t/t7507-commit-verbose.sh +++ b/t/t7507-commit-verbose.sh @@ -65,9 +65,35 @@ test_expect_success 'diff in message is retained without -v' ' check_message diff ' -test_expect_failure 'diff in message is retained with -v' ' +test_expect_success 'diff in message is retained with -v' ' git commit --amend -F diff -v && check_message diff ' +test_expect_success 'submodule log is stripped out too with -v' ' + git config diff.submodule log && + git submodule add ./. sub && + git commit -m "sub added" && + ( + cd sub && + echo "more" >>file && + git commit -a -m "submodule commit" + ) && + ( + GIT_EDITOR=cat && + export GIT_EDITOR && + test_must_fail git commit -a -v 2>err + ) && + test_i18ngrep "Aborting commit due to empty commit message." err +' + +test_expect_success 'verbose diff is stripped out with set core.commentChar' ' + ( + GIT_EDITOR=cat && + export GIT_EDITOR && + test_must_fail git -c core.commentchar=";" commit -a -v 2>err + ) && + test_i18ngrep "Aborting commit due to empty commit message." err +' + test_done diff --git a/transport.c b/transport.c index 7202b7777d..5485e2ab1e 100644 --- a/transport.c +++ b/transport.c @@ -885,14 +885,6 @@ void transport_take_over(struct transport *transport, transport->cannot_reuse = 1; } -static int is_local(const char *url) -{ - const char *colon = strchr(url, ':'); - const char *slash = strchr(url, '/'); - return !colon || (slash && slash < colon) || - has_dos_drive_prefix(url); -} - static int is_file(const char *url) { struct stat buf; @@ -941,7 +933,7 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->fetch = fetch_objs_via_rsync; ret->push = rsync_transport_push; ret->smart_options = NULL; - } else if (is_local(url) && is_file(url) && is_bundle(url, 1)) { + } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->get_refs_list = get_refs_from_bundle; @@ -1297,7 +1289,7 @@ char *transport_anonymize_url(const char *url) size_t anon_len, prefix_len = 0; anon_part = strchr(url, '@'); - if (is_local(url) || !anon_part) + if (url_is_local_not_ssh(url) || !anon_part) goto literal_copy; anon_len = strlen(++anon_part); diff --git a/tree-walk.c b/tree-walk.c index 5ece8c3477..e06f240c75 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -743,7 +743,7 @@ match_wildcards: if (item->nowildcard_len && !match_wildcard_base(item, base_str, baselen, &matched)) - return entry_not_interesting; + continue; /* * Concatenate base and entry->path into one and do diff --git a/wt-status.c b/wt-status.c index b4e44baa29..85390b813f 100644 --- a/wt-status.c +++ b/wt-status.c @@ -16,6 +16,9 @@ #include "column.h" #include "strbuf.h" +static char cut_line[] = +"------------------------ >8 ------------------------\n"; + static char default_wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */ @@ -767,6 +770,18 @@ conclude: status_printf_ln(s, GIT_COLOR_NORMAL, ""); } +void wt_status_truncate_message_at_cut_line(struct strbuf *buf) +{ + const char *p; + struct strbuf pattern = STRBUF_INIT; + + strbuf_addf(&pattern, "%c %s", comment_line_char, cut_line); + p = strstr(buf->buf, pattern.buf); + if (p && (p == buf->buf || p[-1] == '\n')) + strbuf_setlen(buf, p - buf->buf); + strbuf_release(&pattern); +} + static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; @@ -787,10 +802,20 @@ static void wt_status_print_verbose(struct wt_status *s) * If we're not going to stdout, then we definitely don't * want color, since we are going to the commit message * file (and even the "auto" setting won't work, since it - * will have checked isatty on stdout). + * will have checked isatty on stdout). But we then do want + * to insert the scissor line here to reliably remove the + * diff before committing. */ - if (s->fp != stdout) + if (s->fp != stdout) { + const char *explanation = _("Do not touch the line above.\nEverything below will be removed."); + struct strbuf buf = STRBUF_INIT; + rev.diffopt.use_color = 0; + fprintf(s->fp, "%c %s", comment_line_char, cut_line); + strbuf_add_commented_lines(&buf, explanation, strlen(explanation)); + fputs(buf.buf, s->fp); + strbuf_release(&buf); + } run_diff_index(&rev, 1); } diff --git a/wt-status.h b/wt-status.h index 6c29e6f5e5..30a4812583 100644 --- a/wt-status.h +++ b/wt-status.h @@ -91,6 +91,7 @@ struct wt_status_state { unsigned char cherry_pick_head_sha1[20]; }; +void wt_status_truncate_message_at_cut_line(struct strbuf *); void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); void wt_status_collect(struct wt_status *s); |