]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'rk/send-email-ssl-cert' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 13 Feb 2014 21:38:19 +0000 (13:38 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 13 Feb 2014 21:38:19 +0000 (13:38 -0800)
A recent update to "git send-email" broke platforms where
/etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
(e.g. Fedora rawhide).

* rk/send-email-ssl-cert:
  send-email: /etc/ssl/certs/ directory may not be usable as ca_path

35 files changed:
Documentation/RelNotes/1.8.5.4.txt [new file with mode: 0644]
Documentation/git-pull.txt
Documentation/git.txt
Documentation/merge-options.txt
GIT-VERSION-GEN
RelNotes
builtin/add.c
builtin/blame.c
builtin/clone.c
builtin/commit.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/repack.c
commit.c
connect.c
connect.h
fetch-pack.h
git-send-email.perl
git-stash.sh
log-tree.c
perl/Git/SVN/Editor.pm
sha1_file.c
t/annotate-tests.sh
t/t3700-add.sh
t/t3903-stash.sh
t/t4010-diff-pathspec.sh
t/t4205-log-pretty-formats.sh
t/t5500-fetch-pack.sh
t/t5601-clone.sh
t/t6101-rev-parse-parents.sh
t/t7507-commit-verbose.sh
transport.c
tree-walk.c
wt-status.c
wt-status.h

diff --git a/Documentation/RelNotes/1.8.5.4.txt b/Documentation/RelNotes/1.8.5.4.txt
new file mode 100644 (file)
index 0000000..db3b3d3
--- /dev/null
@@ -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.
index 6083aab87bd947c8528cbf347769b6621531b035..200eb22260069af7a9e2e248f0794a73e2cf4a9f 100644 (file)
@@ -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
index 388b19633ea21cbf1e66bb32d7d08c7fcda4b890..36483181cb3ec884bf8d4cf9ce59d502d066e42f 100644 (file)
@@ -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],
index afba8d4f3b2dcc952310c270daf26e01f8b30800..e1343155fad7b2709d2f3700ea3d5b4c4d1a7a89 100644 (file)
@@ -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
index a8f58ee282998b531ac093280b678baccef7e7ca..ccec5effb152aba2c4895710d855cb5cf57990d9 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.5.3
+DEF_VER=v1.8.5.4
 
 LF='
 '
index 8e86db6ab6eeed617bb208dadba417731c162eae..f4ebd653fe8aefa813e4b95b18cadbfbdf22d805 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -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
index 226f758869358444ad1c39e5e0a05c961fb76859..d7e3e44d06cdf56ac661600788cfdf751037226e 100644 (file)
@@ -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))) {
index 1407ae7eb291ab7c0d00984d18820c955703e17f..9047b6ef4caa0aa5ca964cdfafdbc19985a3cb25 100644 (file)
@@ -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;
 }
 
index 874e0fd0b6e3ea4882783c0b2377016d93bd989d..cc11104d4267f61aa5a2aa5472a5c69c1ccd8994 100644 (file)
@@ -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
index 6ab4605cf5c2e6ef5efb37518c9c215bf8895f97..fedb45af8c65d28c3b43b3b74362e589d81a95ee 100644 (file)
@@ -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);
index c8e858232a8e7a3536ef4d296efdc618e034c36e..758b5acd55aadcb43b6d11b02f0555a214b35744 100644 (file)
@@ -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,
index bd7a10164f4fed8aeb6e8148e2ae8c0a793e7ee0..5bd00d064a7fbfb828f7a7c5e79f8ed0a5a1e959 100644 (file)
@@ -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);
index 91e2363c7172ae3db9304e1490234b2b4cfbe381..a2b9dba5223bc23304cdd3b955e65d80366f09f6 100644 (file)
@@ -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)
index de16a3c0a2d6693173678247ba0755e4d7483a1c..57ebea2aee30b00e86a620f7efc793420f214185 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -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;
 }
 
index 06e88b0705f7fbd138e504920c20c70218121696..8a013a723b4d81deb76baabb7615c06b0caa068c 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -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;
 }
 
index 64fb7dbbee8714c034c5e018b3b1b4f8c29f0ea7..c41a6850f1302e4d27af1066b53b20dd303f0d13 100644 (file)
--- a/connect.h
+++ b/connect.h
@@ -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
index 461cbf39b2affa71e27dd1a95c24d6c65a938d62..20ccc12e57b9499b0716c8295b4adea38d8d2a86 100644 (file)
@@ -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,
index 689944f71bf911a25c7d480a3a2869dde4ace7af..fdb0029b597898559376b1b28d692450794251f3 100755 (executable)
@@ -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,
@@ -1215,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;
index 1e541a21257c70fa67c0fee552ccb05fc5b6a280..f0a94abf1434c65d27caf4cd674f89de62e9333c 100755 (executable)
@@ -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()
index 8534d91826f3cf05f810a28728ee8bd51649d819..1982631ca497002b746873cd62fabbc4b7f9d3ce 100644 (file)
@@ -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;
index b3bcd476daa7d4ab32c30c6fbd2f0a73ec9d0b4f..34e8af966c4a97bd3fafd5d9cfecbfb982f78897 100644 (file)
@@ -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);
index 760dd60031bc4de7f0155303da5938c1571a2378..06c809aeeb3a608c09247b4f2146eb246938d6bf 100644 (file)
@@ -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 ;-) */
index c9d105d70725b9a97d5a9518e83c615821e91c23..304c7b7d8714f9f985cddcc91ba3006f668de127 100644 (file)
@@ -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" \
index aab86e838b806f9bb2289f536f4ba9324d75da0a..fe274e2fb14869314dfb21d563fd2c3f367365c8 100755 (executable)
@@ -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 &&
index debda7a678277e1198ba6620210b66984caf03a2..5b79b216e2e3bb837e58828a2e9a292cb2d7cc53 100755 (executable)
@@ -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
index af5134b70c6b4898aa652907d58191d45aa30ac4..589bc6bfb4543324dcf6f166c4db482958f26e63 100755 (executable)
@@ -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
index fb000411395d50639334c3c0395b2b975aa4bc12..2a6278bb333d2843ee617ff69227feae115aefea 100755 (executable)
@@ -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
index d87ddf73b7127bc624ca739653db9389831b817e..5b2b1c2c130387332778f6e49043b739dd2d7d21 100755 (executable)
@@ -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
index 1d1c8755ead4e432744a82f0d7b8ed7dfc8a6510..62fbd7e6649d9215528a83249f1b46735de2237d 100755 (executable)
@@ -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' '
 
        (
index 7ea14ced313d3f0dd20d4afd2fc2a0d3309b938f..10b1452766b613932f66421f6c9bfafecc093177 100755 (executable)
@@ -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
 '
index da5bd3b5a585667dad97481df27049f0aa7415eb..2ddf28c984de99cb17884f76d68a708076f57e12 100755 (executable)
@@ -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
index 7202b7777d804b75eb2ec54f666e81173690678c..5485e2ab1e86fd7f02c2078ed6505cdec292ee4f 100644 (file)
@@ -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);
index 5ece8c3477b11f3bf0c54196924ac24568309225..e06f240c7515ab7b08c4441c3cb48fce1602d0e2 100644 (file)
@@ -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
index b4e44baa2917dfcf33824c3d6fc08756886b9ae1..85390b813f12e2392b73dd6dffe8d1b41e838614 100644 (file)
@@ -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);
 }
 
index 6c29e6f5e57f84eb7acdc3cf1ee621cc717fd5a9..30a481258366733ad5d6a65e3a9c3ae1ee74e833 100644 (file)
@@ -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);