Merge branch 'mm/usage-log-l-can-take-regex' into maint-2.3
authorJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 21:34:01 +0000 (14:34 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 21:34:01 +0000 (14:34 -0700)
Documentation fix.

* mm/usage-log-l-can-take-regex:
log -L: improve error message on malformed argument
Documentation: change -L:<regex> to -L:<funcname>

27 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes/2.3.6.txt [new file with mode: 0644]
Documentation/RelNotes/2.3.7.txt [new file with mode: 0644]
Documentation/git-cherry-pick.txt
Documentation/git-fast-import.txt
Documentation/git.txt
Documentation/gitweb.conf.txt
Documentation/howto/recover-corrupted-object-harder.txt
GIT-VERSION-GEN
RelNotes
builtin/config.c
connect.c
contrib/completion/git-completion.bash
contrib/diff-highlight/diff-highlight
date.c
diff-no-index.c
parse-options.h
path.c
send-pack.c
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/t4053-diff-no-index.sh
t/t5500-fetch-pack.sh
t/t5541-http-push-smart.sh
t/t5551-http-fetch-smart.sh
t/t5601-clone.sh
t/test-lib.sh
index 0f8cccf52da4882377a56042a4de3ff754d357b9..2dd35bd1b8be1b0189a1c1408792f42b9eb0bc3d 100644 (file)
@@ -1,5 +1,5 @@
 Like other projects, we also have some guidelines to keep to the
-code.  For Git in general, three rough rules are:
+code.  For Git in general, a few rough rules are:
 
  - Most importantly, we never say "It's in POSIX; we'll happily
    ignore your needs should your system not conform to it."
diff --git a/Documentation/RelNotes/2.3.6.txt b/Documentation/RelNotes/2.3.6.txt
new file mode 100644 (file)
index 0000000..432f770
--- /dev/null
@@ -0,0 +1,13 @@
+Git v2.3.6 Release Notes
+========================
+
+Fixes since v2.3.5
+------------------
+
+ * "diff-highlight" (in contrib/) used to show byte-by-byte
+   differences, which meant that multi-byte characters can be chopped
+   in the middle.  It learned to pay attention to character boundaries
+   (assuming the UTF-8 payload).
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.3.7.txt b/Documentation/RelNotes/2.3.7.txt
new file mode 100644 (file)
index 0000000..fc95812
--- /dev/null
@@ -0,0 +1,21 @@
+Git v2.3.7 Release Notes
+========================
+
+Fixes since v2.3.6
+------------------
+
+ * An earlier update to the parser that disects a URL broke an
+   address, followed by a colon, followed by an empty string (instead
+   of the port number), e.g. ssh://example.com:/path/to/repo.
+
+ * The completion script (in contrib/) contaminated global namespace
+   and clobbered on a shell variable $x.
+
+ * The "git push --signed" protocol extension did not limit what the
+   "nonce" that is a server-chosen string can contain or how long it
+   can be, which was unnecessarily lax.  Limit both the length and the
+   alphabet to a reasonably small space that can still have enough
+   entropy.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
index 1c03c792b0be98181d1e988d6bd19a4637ce6ec5..1147c71da605c1f5779835137fb6bab5e2c349a6 100644 (file)
@@ -131,7 +131,8 @@ effect to your index in a row.
 --keep-redundant-commits::
        If a commit being cherry picked duplicates a commit already in the
        current history, it will become empty.  By default these
-       redundant commits are ignored.  This option overrides that behavior and
+       redundant commits cause `cherry-pick` to stop so the user can
+       examine the commit. This option overrides that behavior and
        creates an empty commit object.  Implies `--allow-empty`.
 
 --strategy=<strategy>::
index f71fb0134be37f224addb1963ed6d06c5bb8778a..690fed3ea40d3de73a2b6f1c194216b72738da8f 100644 (file)
@@ -507,10 +507,6 @@ omitted when creating a new branch, the first `merge` commit will be
 the first ancestor of the current commit, and the branch will start
 out with no files.  An unlimited number of `merge` commands per
 commit are permitted by fast-import, thereby establishing an n-way merge.
-However Git's other tools never create commits with more than 15
-additional ancestors (forming a 16-way merge).  For this reason
-it is suggested that frontends do not use more than 15 `merge`
-commands per commit; 16, if starting a new, empty branch.
 
 Here `<commit-ish>` is any of the commit specification expressions
 also accepted by `from` (see above).
index 8f5220ce47a663180911d4cd4b783f5df18f9385..8704ffd2ffb8188974bc7b9a717adcccc63af551 100644 (file)
@@ -43,9 +43,11 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.3.5/git.html[documentation for release 2.3.5]
+* link:v2.3.7/git.html[documentation for release 2.3.7]
 
 * release notes for
+  link:RelNotes/2.3.7.txt[2.3.7],
+  link:RelNotes/2.3.6.txt[2.3.6],
   link:RelNotes/2.3.5.txt[2.3.5],
   link:RelNotes/2.3.4.txt[2.3.4],
   link:RelNotes/2.3.3.txt[2.3.3],
index ebe7a6c24cfef75441906a3e4de550b9fd296c0b..b96ac72a3305362ac2c35860f3cbdbedb8c5e419 100644 (file)
@@ -482,7 +482,7 @@ project config.  Per-repository configuration takes precedence over value
 composed from `@git_base_url_list` elements and project name.
 +
 You can setup one single value (single entry/item in this list) at build
-time by setting the `GITWEB_BASE_URL` built-time configuration variable.
+time by setting the `GITWEB_BASE_URL` build-time configuration variable.
 By default it is set to (), i.e. an empty list.  This means that gitweb
 would not try to create project URL (to fetch) from project name.
 
index 23e685d8caf454abfc21a0a271ef6e628b73482b..9c4cd0915fe3f3e14879184f3a474e559130bdef 100644 (file)
@@ -240,3 +240,240 @@ But more importantly, git's hashing and checksumming noticed a problem
 that easily could have gone undetected in another system. The result
 still compiled, but would have caused an interesting bug (that would
 have been blamed on some random commit).
+
+
+The adventure continues...
+--------------------------
+
+I ended up doing this again! Same entity, new hardware. The assumption
+at this point is that the old disk corrupted the packfile, and then the
+corruption was migrated to the new hardware (because it was done by
+rsync or similar, and no fsck was done at the time of migration).
+
+This time, the affected blob was over 20 megabytes, which was far too
+large to do a brute-force on. I followed the instructions above to
+create the `zlib` file. I then used the `inflate` program below to pull
+the corrupted data from that. Examining that output gave me a hint about
+where in the file the corruption was. But now I was working with the
+file itself, not the zlib contents. So knowing the sha1 of the object
+and the approximate area of the corruption, I used the `sha1-munge`
+program below to brute-force the correct byte.
+
+Here's the inflate program (it's essentially `gunzip` but without the
+`.gz` header processing):
+
+--------------------------
+#include <stdio.h>
+#include <string.h>
+#include <zlib.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+       /*
+        * oversized so we can read the whole buffer in;
+        * this could actually be switched to streaming
+        * to avoid any memory limitations
+        */
+       static unsigned char buf[25 * 1024 * 1024];
+       static unsigned char out[25 * 1024 * 1024];
+       int len;
+       z_stream z;
+       int ret;
+
+       len = read(0, buf, sizeof(buf));
+       memset(&z, 0, sizeof(z));
+       inflateInit(&z);
+
+       z.next_in = buf;
+       z.avail_in = len;
+       z.next_out = out;
+       z.avail_out = sizeof(out);
+
+       ret = inflate(&z, 0);
+       if (ret != Z_OK && ret != Z_STREAM_END)
+               fprintf(stderr, "initial inflate failed (%d)\n", ret);
+
+       fprintf(stderr, "outputting %lu bytes", z.total_out);
+       fwrite(out, 1, z.total_out, stdout);
+       return 0;
+}
+--------------------------
+
+And here is the `sha1-munge` program:
+
+--------------------------
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <openssl/sha.h>
+#include <stdlib.h>
+
+/* eye candy */
+static int counter = 0;
+static void progress(int sig)
+{
+       fprintf(stderr, "\r%d", counter);
+       alarm(1);
+}
+
+static const signed char hexval_table[256] = {
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 00-07 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 08-0f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 10-17 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 18-1f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 20-27 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 28-2f */
+         0,  1,  2,  3,  4,  5,  6,  7,                /* 30-37 */
+         8,  9, -1, -1, -1, -1, -1, -1,                /* 38-3f */
+        -1, 10, 11, 12, 13, 14, 15, -1,                /* 40-47 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 48-4f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 50-57 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 58-5f */
+        -1, 10, 11, 12, 13, 14, 15, -1,                /* 60-67 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 68-67 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 70-77 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 78-7f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 80-87 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 88-8f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 90-97 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 98-9f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* a0-a7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* a8-af */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* b0-b7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* b8-bf */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* c0-c7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* c8-cf */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* d0-d7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* d8-df */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* e0-e7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* e8-ef */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* f0-f7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* f8-ff */
+};
+
+static inline unsigned int hexval(unsigned char c)
+{
+return hexval_table[c];
+}
+
+static int get_sha1_hex(const char *hex, unsigned char *sha1)
+{
+       int i;
+       for (i = 0; i < 20; i++) {
+               unsigned int val;
+               /*
+                * hex[1]=='\0' is caught when val is checked below,
+                * but if hex[0] is NUL we have to avoid reading
+                * past the end of the string:
+                */
+               if (!hex[0])
+                       return -1;
+               val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+               if (val & ~0xff)
+                       return -1;
+               *sha1++ = val;
+               hex += 2;
+       }
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       /* oversized so we can read the whole buffer in */
+       static unsigned char buf[25 * 1024 * 1024];
+       char header[32];
+       int header_len;
+       unsigned char have[20], want[20];
+       int start, len;
+       SHA_CTX orig;
+       unsigned i, j;
+
+       if (!argv[1] || get_sha1_hex(argv[1], want)) {
+               fprintf(stderr, "usage: sha1-munge <sha1> [start] <file.in\n");
+               return 1;
+       }
+
+       if (argv[2])
+               start = atoi(argv[2]);
+       else
+               start = 0;
+
+       len = read(0, buf, sizeof(buf));
+       header_len = sprintf(header, "blob %d", len) + 1;
+       fprintf(stderr, "using header: %s\n", header);
+
+       /*
+        * We keep a running sha1 so that if you are munging
+        * near the end of the file, we do not have to re-sha1
+        * the unchanged earlier bytes
+        */
+       SHA1_Init(&orig);
+       SHA1_Update(&orig, header, header_len);
+       if (start)
+               SHA1_Update(&orig, buf, start);
+
+       signal(SIGALRM, progress);
+       alarm(1);
+
+       for (i = start; i < len; i++) {
+               unsigned char c;
+               SHA_CTX x;
+
+#if 0
+               /*
+                * deletion -- this would not actually work in practice,
+                * I think, because we've already committed to a
+                * particular size in the header. Ditto for addition
+                * below. In those cases, you'd have to do the whole
+                * sha1 from scratch, or possibly keep three running
+                * "orig" sha1 computations going.
+                */
+               memcpy(&x, &orig, sizeof(x));
+               SHA1_Update(&x, buf + i + 1, len - i - 1);
+               SHA1_Final(have, &x);
+               if (!memcmp(have, want, 20))
+                       printf("i=%d, deletion\n", i);
+#endif
+
+               /*
+                * replacement -- note that this tries each of the 256
+                * possible bytes. If you suspect a single-bit flip,
+                * it would be much shorter to just try the 8
+                * bit-flipped variants.
+                */
+               c = buf[i];
+               for (j = 0; j <= 0xff; j++) {
+                       buf[i] = j;
+
+                       memcpy(&x, &orig, sizeof(x));
+                       SHA1_Update(&x, buf + i, len - i);
+                       SHA1_Final(have, &x);
+                       if (!memcmp(have, want, 20))
+                               printf("i=%d, j=%02x\n", i, j);
+               }
+               buf[i] = c;
+
+#if 0
+               /* addition */
+               for (j = 0; j <= 0xff; j++) {
+                       unsigned char extra = j;
+                       memcpy(&x, &orig, sizeof(x));
+                       SHA1_Update(&x, &extra, 1);
+                       SHA1_Update(&x, buf + i, len - i);
+                       SHA1_Final(have, &x);
+                       if (!memcmp(have, want, 20))
+                               printf("i=%d, addition=%02x", i, j);
+               }
+#endif
+
+               SHA1_Update(&orig, buf + i, 1);
+               counter++;
+       }
+
+       alarm(0);
+       fprintf(stderr, "\r%d\n", counter);
+       return 0;
+}
+--------------------------
index 7e0ccef568eae0f85f571ed3470fbeee22886b3d..0c1ee67b406523322d7d3ca6ebbcb7c53133d177 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.3.5
+DEF_VER=v2.3.7
 
 LF='
 '
index 99d78b71a0077b3982da174ebd04873dbc335705..8f376a9f834dc1a9717697de76b6f7b3a57d9d73 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.3.5.txt
\ No newline at end of file
+Documentation/RelNotes/2.3.7.txt
\ No newline at end of file
index 15a7bea936d667042cef27f83c86a863df2caa8f..73dc2f1024ad986a2421b0c6e9c5845574437d41 100644 (file)
@@ -455,9 +455,9 @@ static char *default_user_config(void)
        struct strbuf buf = STRBUF_INIT;
        strbuf_addf(&buf,
                    _("# This is Git's per-user configuration file.\n"
-                     "[core]\n"
+                     "[user]\n"
                      "# Please adapt and uncomment the following lines:\n"
-                     "#        user = %s\n"
+                     "#        name = %s\n"
                      "#        email = %s\n"),
                    ident_default_name(),
                    ident_default_email());
index ce0e1214234244236a407e9f3004e619d26c54a8..14c924b030cc17e083d4b8662faf5c6d48f68d85 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -310,6 +310,8 @@ static void get_host_and_port(char **host, const char **port)
                if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) {
                        *colon = 0;
                        *port = colon + 1;
+               } else if (!colon[1]) {
+                       *colon = 0;
                }
        }
 }
index 661a8294dac162f0e50ccfe588847bb45b572143..16205467b1303100b5d67f55371aff749ff5c57d 100644 (file)
@@ -186,7 +186,7 @@ fi
 
 __gitcompappend ()
 {
-       local i=${#COMPREPLY[@]}
+       local i=${#COMPREPLY[@]}
        for x in $1; do
                if [[ "$x" == "$3"* ]]; then
                        COMPREPLY[i++]="$2$x$4"
index 08c88bbc87e51e25cacc5826b26a223f3bfbd382..ffefc31a98a26dfd65d188bbb547cc114231c13d 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/perl
 
+use 5.008;
 use warnings FATAL => 'all';
 use strict;
 
@@ -164,8 +165,12 @@ sub highlight_pair {
 
 sub split_line {
        local $_ = shift;
-       return map { /$COLOR/ ? $_ : (split //) }
-              split /($COLOR*)/;
+       return utf8::decode($_) ?
+               map { utf8::encode($_); $_ }
+                       map { /$COLOR/ ? $_ : (split //) }
+                       split /($COLOR+)/ :
+               map { /$COLOR/ ? $_ : (split //) }
+               split /($COLOR+)/;
 }
 
 sub highlight_line {
diff --git a/date.c b/date.c
index 3eba2dfe8841cee28850e2f1f4177e1e32f1c8a8..733d1b29b19fc7dda04d599eb6a311e809212775 100644 (file)
--- a/date.c
+++ b/date.c
@@ -704,10 +704,17 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
                date += match;
        }
 
-       /* mktime uses local timezone */
+       /* do not use mktime(), which uses local timezone, here */
        *timestamp = tm_to_time_t(&tm);
+       if (*timestamp == -1)
+               return -1;
+
        if (*offset == -1) {
-               time_t temp_time = mktime(&tm);
+               time_t temp_time;
+
+               /* gmtime_r() in match_digit() may have clobbered it */
+               tm.tm_isdst = -1;
+               temp_time = mktime(&tm);
                if ((time_t)*timestamp > temp_time) {
                        *offset = ((time_t)*timestamp - temp_time) / 60;
                } else {
@@ -715,9 +722,6 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
                }
        }
 
-       if (*timestamp == -1)
-               return -1;
-
        if (!tm_gmt)
                *timestamp -= *offset * 60;
        return 0; /* success */
index 265709ba8c51a4390fad11c7d1aa23551a4fd266..0320605a84178ffb2ab9384b8ee9fbac7df16a73 100644 (file)
@@ -97,8 +97,27 @@ static int queue_diff(struct diff_options *o,
        if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
                return -1;
 
-       if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
-               return error("file/directory conflict: %s, %s", name1, name2);
+       if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) {
+               struct diff_filespec *d1, *d2;
+
+               if (S_ISDIR(mode1)) {
+                       /* 2 is file that is created */
+                       d1 = noindex_filespec(NULL, 0);
+                       d2 = noindex_filespec(name2, mode2);
+                       name2 = NULL;
+                       mode2 = 0;
+               } else {
+                       /* 1 is file that is deleted */
+                       d1 = noindex_filespec(name1, mode1);
+                       d2 = noindex_filespec(NULL, 0);
+                       name1 = NULL;
+                       mode1 = 0;
+               }
+               /* emit that file */
+               diff_queue(&diff_queued_diff, d1, d2);
+
+               /* and then let the entire directory be created or deleted */
+       }
 
        if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
                struct strbuf buffer1 = STRBUF_INIT;
@@ -182,12 +201,50 @@ static int queue_diff(struct diff_options *o,
        }
 }
 
+/* append basename of F to D */
+static void append_basename(struct strbuf *path, const char *dir, const char *file)
+{
+       const char *tail = strrchr(file, '/');
+
+       strbuf_addstr(path, dir);
+       while (path->len && path->buf[path->len - 1] == '/')
+               path->len--;
+       strbuf_addch(path, '/');
+       strbuf_addstr(path, tail ? tail + 1 : file);
+}
+
+/*
+ * DWIM "diff D F" into "diff D/F F" and "diff F D" into "diff F D/F"
+ * Note that we append the basename of F to D/, so "diff a/b/file D"
+ * becomes "diff a/b/file D/file", not "diff a/b/file D/a/b/file".
+ */
+static void fixup_paths(const char **path, struct strbuf *replacement)
+{
+       unsigned int isdir0, isdir1;
+
+       if (path[0] == file_from_standard_input ||
+           path[1] == file_from_standard_input)
+               return;
+       isdir0 = is_directory(path[0]);
+       isdir1 = is_directory(path[1]);
+       if (isdir0 == isdir1)
+               return;
+       if (isdir0) {
+               append_basename(replacement, path[0], path[1]);
+               path[0] = replacement->buf;
+       } else {
+               append_basename(replacement, path[1], path[0]);
+               path[1] = replacement->buf;
+       }
+}
+
 void diff_no_index(struct rev_info *revs,
                   int argc, const char **argv,
                   const char *prefix)
 {
        int i, prefixlen;
        const char *paths[2];
+       struct strbuf replacement = STRBUF_INIT;
 
        diff_setup(&revs->diffopt);
        for (i = 1; i < argc - 2; ) {
@@ -217,6 +274,9 @@ void diff_no_index(struct rev_info *revs,
                        p = xstrdup(prefix_filename(prefix, prefixlen, p));
                paths[i] = p;
        }
+
+       fixup_paths(paths, &replacement);
+
        revs->diffopt.skip_stat_unmatch = 1;
        if (!revs->diffopt.output_format)
                revs->diffopt.output_format = DIFF_FORMAT_PATCH;
@@ -235,6 +295,8 @@ void diff_no_index(struct rev_info *revs,
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
 
+       strbuf_release(&replacement);
+
        /*
         * The return code for --no-index imitates diff(1):
         * 0 = no changes, 1 = changes, else error
index 7940bc71af4c6dacd65d042091454c8fa83c53c7..c71e9da4f820ab8e72ff95afb656faece7f1a252 100644 (file)
@@ -95,8 +95,7 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
  *
  * `defval`::
  *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
- *   OPTION_{BIT,SET_INT} store the {mask,integer,pointer} to put in
- *   the value when met.
+ *   OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
  *   CALLBACKS can use it like they want.
  */
 struct option {
diff --git a/path.c b/path.c
index e6089938018b74fb8a6ea547ffc64d428a13daa0..595da81ca67096bae9592d9455bdade442b92628 100644 (file)
--- a/path.c
+++ b/path.c
@@ -303,14 +303,9 @@ char *expand_user_path(const char *path)
  * (3) "relative/path" to mean cwd relative directory; or
  * (4) "/absolute/path" to mean absolute directory.
  *
- * Unless "strict" is given, we try access() for existence of "%s.git/.git",
- * "%s/.git", "%s.git", "%s" in this order.  The first one that exists is
- * what we try.
- *
- * Second, we try chdir() to that.  Upon failure, we return NULL.
- *
- * Then, we try if the current directory is a valid git repository.
- * Upon failure, we return NULL.
+ * Unless "strict" is given, we check "%s/.git", "%s", "%s.git/.git", "%s.git"
+ * in this order. We select the first one that is a valid git repository, and
+ * chdir() to it. If none match, or we fail to chdir, we return NULL.
  *
  * If all goes well, we return the directory we used to chdir() (but
  * before ~user is expanded), avoiding getcwd() resolving symbolic
index 25947d7df9dd3af6e665d5d5eb63ec970617aef1..677bac31930298a7cc4c0087aef8b62fb10249f2 100644 (file)
@@ -281,6 +281,28 @@ static int generate_push_cert(struct strbuf *req_buf,
        return update_seen;
 }
 
+#define NONCE_LEN_LIMIT 256
+
+static void reject_invalid_nonce(const char *nonce, int len)
+{
+       int i = 0;
+
+       if (NONCE_LEN_LIMIT <= len)
+               die("the receiving end asked to sign an invalid nonce <%.*s>",
+                   len, nonce);
+
+       for (i = 0; i < len; i++) {
+               int ch = nonce[i] & 0xFF;
+               if (isalnum(ch) ||
+                   ch == '-' || ch == '.' ||
+                   ch == '/' || ch == '+' ||
+                   ch == '=' || ch == '_')
+                       continue;
+               die("the receiving end asked to sign an invalid nonce <%.*s>",
+                   len, nonce);
+       }
+}
+
 int send_pack(struct send_pack_args *args,
              int fd[], struct child_process *conn,
              struct ref *remote_refs,
@@ -323,6 +345,7 @@ int send_pack(struct send_pack_args *args,
                push_cert_nonce = server_feature_value("push-cert", &len);
                if (!push_cert_nonce)
                        die(_("the receiving end does not support --signed push"));
+               reject_invalid_nonce(push_cert_nonce, len);
                push_cert_nonce = xmemdupz(push_cert_nonce, len);
        }
 
index d154d1ed1dd8f3449ad21e0aeefdce7d3120e1fb..e6adf2f82d59027279e06e0d273e719226d82184 100644 (file)
@@ -79,6 +79,7 @@ HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www
 # hack to suppress apache PassEnv warnings
 GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND
 GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS
+GIT_TRACE=$GIT_TRACE; export GIT_TRACE
 
 if ! test -x "$LIB_HTTPD_PATH"
 then
index 03a4c2ee842e51e13b14774f1f86a4e7b22ae10c..0b81a0047b8d9cd60266500907e95ddc5b87742c 100644 (file)
@@ -70,6 +70,7 @@ PassEnv GIT_VALGRIND
 PassEnv GIT_VALGRIND_OPTIONS
 PassEnv GNUPGHOME
 PassEnv ASAN_OPTIONS
+PassEnv GIT_TRACE
 
 Alias /dumb/ www/
 Alias /auth/dumb/ www/auth/dumb/
index 2ab3c487340569d7f2f8164776907ef30df2d415..596dfe712d5e870cbc1a5b88358127d80d0f570c 100755 (executable)
@@ -55,4 +55,38 @@ test_expect_success 'git diff --no-index executed outside repo gives correct err
        )
 '
 
+test_expect_success 'diff D F and diff F D' '
+       (
+               cd repo &&
+               echo in-repo >a &&
+               echo non-repo >../non/git/a &&
+               mkdir sub &&
+               echo sub-repo >sub/a &&
+
+               test_must_fail git diff --no-index sub/a ../non/git/a >expect &&
+               test_must_fail git diff --no-index sub/a ../non/git/ >actual &&
+               test_cmp expect actual &&
+
+               test_must_fail git diff --no-index a ../non/git/a >expect &&
+               test_must_fail git diff --no-index a ../non/git/ >actual &&
+               test_cmp expect actual &&
+
+               test_must_fail git diff --no-index ../non/git/a a >expect &&
+               test_must_fail git diff --no-index ../non/git a >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'turning a file into a directory' '
+       (
+               cd non/git &&
+               mkdir d e e/sub &&
+               echo 1 >d/sub &&
+               echo 2 >e/sub/file &&
+               printf "D\td/sub\nA\te/sub/file\n" >expect &&
+               test_must_fail git diff --no-index --name-status d e >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done
index bd37f040b6ce13406ef009944d46d2f1cc6c8d7b..ed404073095ffb607fc6e54d6c92be389dc97bfb 100755 (executable)
@@ -576,13 +576,16 @@ do
        do
                for h in host user@host user@[::1] user@::1
                do
-                       test_expect_success "fetch-pack --diag-url $p://$h/$r" '
-                               check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r"
-                       '
-                       # "/~" -> "~" conversion
-                       test_expect_success "fetch-pack --diag-url $p://$h/~$r" '
-                               check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r"
-                       '
+                       for c in "" :
+                       do
+                               test_expect_success "fetch-pack --diag-url $p://$h$c/$r" '
+                                       check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r"
+                               '
+                               # "/~" -> "~" conversion
+                               test_expect_success "fetch-pack --diag-url $p://$h$c/~$r" '
+                                       check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r"
+                               '
+                       done
                done
                for h in host User@host User@[::1]
                do
index d2c681ebfde39fcccef190c3a242dfae9d8af2f2..1ecb5881acf720e7c0dc8b885750f6e641764591 100755 (executable)
@@ -324,12 +324,6 @@ test_expect_success 'push into half-auth-complete requires password' '
        test_cmp expect actual
 '
 
-run_with_limited_cmdline () {
-       (ulimit -s 128 && "$@")
-}
-
-test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true'
-
 test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' '
        sha1=$(git rev-parse HEAD) &&
        test_seq 2000 |
index b97077351ddd8f4dd29ddb1931754b0b83f4d808..df47851752f6b9b085d0feab8d6ba24ef2d0da29 100755 (executable)
@@ -224,10 +224,10 @@ test_expect_success 'transfer.hiderefs works over smart-http' '
        git -C hidden.git rev-parse --verify b
 '
 
-test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
+test_expect_success 'create 2,000 tags in the repo' '
        (
        cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
-       for i in `test_seq 50000`
+       for i in $(test_seq 2000)
        do
                echo "commit refs/heads/too-many-refs"
                echo "mark :$i"
@@ -248,13 +248,22 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
        )
 '
 
-test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' '
-       git clone $HTTPD_URL/smart/repo.git too-many-refs &&
+test_expect_success CMDLINE_LIMIT \
+       'clone the 2,000 tag repo to check OS command line overflow' '
+       run_with_limited_cmdline git clone $HTTPD_URL/smart/repo.git too-many-refs &&
        (
                cd too-many-refs &&
-               test $(git for-each-ref refs/tags | wc -l) = 50000
+               git for-each-ref refs/tags >actual &&
+               test_line_count = 2000 actual
        )
 '
 
+test_expect_success 'large fetch-pack requests can be split across POSTs' '
+       GIT_CURL_VERBOSE=1 git -c http.postbuffer=65536 \
+               clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err &&
+       grep "^> POST" err >posts &&
+       test_line_count = 2 posts
+'
+
 stop_httpd
 test_done
index 02b40b117faa1c6de816001018d1c7deda15ad7d..1befc453a31e6ad67c3805eb94bfe00f6b7a5469 100755 (executable)
@@ -387,14 +387,17 @@ do
 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"
+#ignore trailing colon
+for tcol in "" :
+do
+       test_expect_success "clone ssh://host.xz$tcol/home/user/repo" '
+               test_clone_url "ssh://host.xz$tcol/home/user/repo" host.xz /home/user/repo
+       '
+       # from home directory
+       test_expect_success "clone ssh://host.xz$tcol/~repo" '
+       test_clone_url "ssh://host.xz$tcol/~repo" host.xz "~repo"
 '
+done
 
 # with port number
 test_expect_success 'clone ssh://host.xz:22/home/user/repo' '
@@ -407,9 +410,9 @@ test_expect_success 'clone ssh://host.xz:22/~repo' '
 '
 
 #IPv6
-for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
+for tuah in ::1 [::1] [::1]: user@::1 user@[::1] user@[::1]: [user@::1] [user@::1]:
 do
-       ehost=$(echo $tuah | tr -d "[]")
+       ehost=$(echo $tuah | sed -e "s/1]:/1]/ "| tr -d "[]")
        test_expect_success "clone ssh://$tuah/home/user/repo" "
          test_clone_url ssh://$tuah/home/user/repo $ehost /home/user/repo
        "
index c09677802cce067a946a2550cdd2d8ef33434e81..9914d3e1cfe20f09b47fdc02896dc18ed0f61e45 100644 (file)
@@ -152,10 +152,7 @@ unset UNZIP
 
 case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
 1|2|true)
-       echo "* warning: Some tests will not work if GIT_TRACE" \
-               "is set as to trace on STDERR ! *"
-       echo "* warning: Please set GIT_TRACE to something" \
-               "other than 1, 2 or true ! *"
+       GIT_TRACE=4
        ;;
 esac
 
@@ -299,6 +296,7 @@ die () {
 
 GIT_EXIT_OK=
 trap 'die' EXIT
+trap 'exit $?' INT
 
 # The user-facing functions are loaded from a separate file so that
 # test_perf subshells can have them too
@@ -1064,3 +1062,9 @@ test_lazy_prereq UNZIP '
        "$GIT_UNZIP" -v
        test $? -ne 127
 '
+
+run_with_limited_cmdline () {
+       (ulimit -s 128 && "$@")
+}
+
+test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true'