Imported Upstream version 2.3.6 upstream/2.3.6
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:14:57 +0000 (15:14 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:14:57 +0000 (15:14 +0900)
17 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes/2.3.6.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
contrib/diff-highlight/diff-highlight
parse-options.h
path.c
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/t5541-http-push-smart.sh
t/t5551-http-fetch-smart.sh
t/test-lib.sh

index 0f8cccf..2dd35bd 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.
index 1c03c79..1147c71 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 f71fb01..690fed3 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 8f5220c..085bc34 100644 (file)
@@ -43,9 +43,10 @@ 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.6/git.html[documentation for release 2.3.6]
 
 * release notes for
+  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 ebe7a6c..b96ac72 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 23e685d..9c4cd09 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 7e0ccef..3baaa9d 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.3.5
+DEF_VER=v2.3.6
 
 LF='
 '
index 99d78b7..d92e7b8 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.3.5.txt
\ No newline at end of file
+Documentation/RelNotes/2.3.6.txt
\ No newline at end of file
index 08c88bb..ffefc31 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 {
index 7940bc7..c71e9da 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 e608993..595da81 100644 (file)
--- a/path.c
+++ b/path.c
@@ -303,14 +303,9 @@ return_null:
  * (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 d154d1e..e6adf2f 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 03a4c2e..0b81a00 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 d2c681e..1ecb588 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 b970773..df47851 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 c096778..9914d3e 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'