{"thread":{"id":"29222","subject":"[PATCH 3/6] Add MD support for packfiles, fast-import, and pruning.","startedAt":"2011-12-21T07:11:16Z","lastAt":"2011-12-21T07:11:16Z","messageCount":1,"participants":["Bill Zaumen"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"181564","messageId":"1324451476.1684.21.camel@yos","threadId":"29222","inReplyTo":null,"subject":"[PATCH 3/6] Add MD support for packfiles, fast-import, and pruning.","fromName":"Bill Zaumen","fromEmail":"bill.zaumen+git@gmail.com","sentAt":"2011-12-21T07:11:16Z","receivedAt":"2011-12-21T07:11:16Z","isPatch":true,"sender":{"key":"bill.zaumen+git@gmail.com","avatar":null},"body":"The utilities for creating and querying pack files,\nfor the fast-import of files, and for pruning a\ngit repository were modified to support message digests\n(either in individual files or in 'mds' files that\nparallel pack index files).\n\nSigned-off-by: Bill Zaumen <bill.zaumen+git@gmail.com>\n---\n builtin/count-objects.c   |   92 +++++++++++++++++++++++++++++-\n builtin/index-pack.c      |  139 +++++++++++++++++++++++++++++++++++++++++----\n builtin/pack-objects.c    |   81 ++++++++++++++++++++++++++-\n builtin/pack-redundant.c  |   14 ++++-\n builtin/prune-packed.c    |   21 ++++++-\n builtin/prune.c           |    1 +\n builtin/verify-pack.c     |   14 ++++-\n fast-import.c             |   77 ++++++++++++++++++++++++-\n git-repack.sh             |   12 +++-\n t/t5300-pack-object.sh    |   17 +++++-\n t/t5301-sliding-window.sh |   14 ++++-\n t/t5302-pack-index.sh     |    6 +-\n t/t5304-prune.sh          |   13 +++--\n t/t9300-fast-import.sh    |    8 ++-\n 14 files changed, 467 insertions(+), 42 deletions(-)\n\ndiff --git a/builtin/count-objects.c b/builtin/count-objects.c\nindex c37cb98..47135e1 100644\n--- a/builtin/count-objects.c\n+++ b/builtin/count-objects.c\n@@ -8,6 +8,12 @@\n #include \"dir.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"mdsdb.h\"\n+\n+int mdsmode = 0;\n+unsigned long has_loose_mds = 0;\n+unsigned long loose_mds_missing = 0;\n+\n \n static void count_objects(DIR *d, char *path, int len, int verbose,\n \t\t\t  unsigned long *loose,\n@@ -53,20 +59,37 @@ static void count_objects(DIR *d, char *path, int len, int verbose,\n \t\t\tcontinue;\n \t\t}\n \t\t(*loose)++;\n-\t\tif (!verbose)\n+\t\tif (!verbose) {\n+\t\t\tif (mdsmode) {\n+\t\t\t\tif (get_sha1_hex(hex, sha1)) {\n+\t\t\t\t\tdie(\"internal error\");\n+\t\t\t\t} else if (mdsdb_lookup(NULL, sha1, NULL) > 0) {\n+\t\t\t\t\thas_loose_mds++;\n+\t\t\t\t} else {\n+\t\t\t\t\tloose_mds_missing++;\n+\t\t\t\t}\n+\t\t\t}\n \t\t\tcontinue;\n+\t\t}\n \t\tmemcpy(hex, path+len, 2);\n \t\tmemcpy(hex+2, ent->d_name, 38);\n \t\thex[40] = 0;\n \t\tif (get_sha1_hex(hex, sha1))\n \t\t\tdie(\"internal error\");\n+\t\tif (mdsmode) {\n+\t\t\tif (mdsdb_lookup(NULL, sha1, NULL) > 0) {\n+\t\t\t\thas_loose_mds++;\n+\t\t\t} else {\n+\t\t\t\tloose_mds_missing++;\n+\t\t\t}\n+\t\t}\n \t\tif (has_sha1_pack(sha1))\n \t\t\t(*packed_loose)++;\n \t}\n }\n \n static char const * const count_objects_usage[] = {\n-\t\"git count-objects [-v]\",\n+\t\"git count-objects [-v] [-M]\",\n \tNULL\n };\n \n@@ -80,6 +103,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \toff_t loose_size = 0;\n \tstruct option opts[] = {\n \t\tOPT__VERBOSE(&verbose, \"be verbose\"),\n+\t\tOPT_BOOLEAN('M', \"count-md\", &mdsmode,\n+\t\t\t    \"count MDs (Message Digests)\"),\n \t\tOPT_END(),\n \t};\n \n@@ -90,6 +115,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \tmemcpy(path, objdir, len);\n \tif (len && objdir[len-1] != '/')\n \t\tpath[len++] = '/';\n+\tmdsdb_open(NULL);\n \tfor (i = 0; i < 256; i++) {\n \t\tDIR *d;\n \t\tsprintf(path + len, \"%02x\", i);\n@@ -100,10 +126,16 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\t      &loose, &loose_size, &packed_loose, &garbage);\n \t\tclosedir(d);\n \t}\n+\tmdsdb_close(NULL);\n \tif (verbose) {\n \t\tstruct packed_git *p;\n \t\tunsigned long num_pack = 0;\n \t\toff_t size_pack = 0;\n+\t\tunsigned long mds_mismatched = 0;\n+\t\tunsigned long missing_mdsfile_count = 0;\n+\t\tunsigned long mds_count = 0;\n+\t\tint wsize = 0;\n+\t\tmdigest_t digest;\n \t\tif (!packed_git)\n \t\t\tprepare_packed_git();\n \t\tfor (p = packed_git; p; p = p->next) {\n@@ -114,6 +146,40 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\tpacked += p->num_objects;\n \t\t\tsize_pack += p->pack_size + p->index_size;\n \t\t\tnum_pack++;\n+\t\t\tif (!mdsmode)\n+\t\t\t\tcontinue;\n+\t\t\tif (open_pack_mds(p)) {\n+\t\t\t\tmissing_mdsfile_count++;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * Assume mds version 1 for now. We check that\n+\t\t\t * the mds file has the right size and record if it\n+\t\t\t * doesn't.  If it is the right size, we go through\n+\t\t\t * all the entries and count the number of sha1 hashes\n+\t\t\t * for which there is a recorded CRC.  We do not\n+\t\t\t * check if the CRC is the right one for the\n+\t\t\t * corresponding object: run git pack-verify to do\n+\t\t\t * that.\n+\t\t\t */\n+\t\t\tif (p->mds_size > 7) {\n+\t\t\t  wsize = ((unsigned char *)(p->mds_data))[7] * 4;\n+\t\t\t}\n+\t\t\tif (p->mds_size == (size_t)8 +\n+\t\t\t    (((size_t)\n+\t\t\t      ((p->num_objects)/4 + (p->num_objects % 4 != 0))\n+\t\t\t      * (size_t)4 * (size_t)(1 + wsize)) +\n+\t\t\t     (size_t)(20 * 2))) {\n+\t\t\t\tfor (i = 0; i < p->num_objects; i++) {\n+\t\t\t\t\tmds_count +=\n+\t\t\t\t\t  (nth_packed_object_mdigest(p,\n+\t\t\t\t\t\t\t\t      i,\n+\t\t\t\t\t\t\t\t      &digest)\n+\t\t\t\t\t   == 1);\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t  mds_mismatched++;\n+\t\t\t}\n \t\t}\n \t\tprintf(\"count: %lu\\n\", loose);\n \t\tprintf(\"size: %lu\\n\", (unsigned long) (loose_size / 1024));\n@@ -122,9 +188,31 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\tprintf(\"size-pack: %lu\\n\", (unsigned long) (size_pack / 1024));\n \t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n \t\tprintf(\"garbage: %lu\\n\", garbage);\n+\t\tif (mdsmode) {\n+\t\t\tif (missing_mdsfile_count) {\n+\t\t\t\tprintf(\"missing MD (Message Digest) \"\n+\t\t\t\t       \"files: %lu\\n\",\n+\t\t\t\t\tmissing_mdsfile_count);\n+\t\t\t}\n+\t\t\tif (mds_mismatched)\n+\t\t\t\tprintf(\"MD (Message Digest) files with\"\n+\t\t\t\t       \" wrong size: %lu \"\n+\t\t\t\t       \"(file extension = .mds)\\n\",\n+\t\t\t\t\tmds_mismatched);\n+\t\t\tif (packed != mds_count) {\n+\t\t\t\tprintf(\"missing MD (Message Digest)\"\n+\t\t\t\t       \" count: %lu\\n\",\n+\t\t\t\t       packed - mds_count);\n+\t\t\t}\n+\t\t}\n \t}\n \telse\n \t\tprintf(\"%lu objects, %lu kilobytes\\n\",\n \t\t       loose, (unsigned long) (loose_size / 1024));\n+\tif (mdsmode && loose_mds_missing) {\n+\t\tassert(loose == (loose_mds_missing + has_loose_mds));\n+\t\tprintf(\"%lu loose objects with no MD (Message Digest)\\n\",\n+\t\t       loose_mds_missing);\n+\t}\n \treturn 0;\n }\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 98025da..127f879 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -1,3 +1,4 @@\n+#include <unistd.h>\n #include \"builtin.h\"\n #include \"delta.h\"\n #include \"pack.h\"\n@@ -23,6 +24,14 @@ struct object_entry {\n \tint base_object_no;\n };\n \n+static int sha1_compare(const void *_a, const void *_b)\n+{\n+\tstruct object_entry *a = (struct object_entry *)_a;\n+\tstruct object_entry *b = (struct object_entry *)_b;\n+\treturn hashcmp(a->idx.sha1, b->idx.sha1);\n+}\n+\n+\n union delta_base {\n \tunsigned char sha1[20];\n \toff_t offset;\n@@ -447,9 +456,10 @@ static void find_delta_children(const union delta_base *base,\n }\n \n static void sha1_object(const void *data, unsigned long size,\n-\t\t\tenum object_type type, unsigned char *sha1)\n+\t\t\tenum object_type type, unsigned char *sha1,\n+\t\t\tmdigest_t *digestp)\n {\n-\thash_sha1_file(data, size, typename(type), sha1);\n+\thash_sha1_file_extended(data, size, typename(type), sha1, digestp);\n \tif (has_sha1_file(sha1)) {\n \t\tvoid *has_data;\n \t\tenum object_type has_type;\n@@ -549,7 +559,8 @@ static void resolve_delta(struct object_entry *delta_obj,\n \tif (!result->data)\n \t\tbad_object(delta_obj->idx.offset, \"failed to apply delta\");\n \tsha1_object(result->data, result->size, delta_obj->real_type,\n-\t\t    delta_obj->idx.sha1);\n+\t\t    delta_obj->idx.sha1, &(delta_obj->idx.digest));\n+\tdelta_obj->idx.has_digest = 1;\n \tnr_resolved_deltas++;\n }\n \n@@ -643,8 +654,12 @@ static void parse_pack_objects(unsigned char *sha1)\n \t\t\tnr_deltas++;\n \t\t\tdelta->obj_no = i;\n \t\t\tdelta++;\n-\t\t} else\n-\t\t\tsha1_object(data, obj->size, obj->type, obj->idx.sha1);\n+\t\t} else {\n+\t\t  sha1_object(data, obj->size, obj->type, obj->idx.sha1,\n+\t\t\t      &(obj->idx.digest));\n+\t\t  obj->idx.has_digest = 1;\n+\t\t}\n+\n \t\tfree(data);\n \t\tdisplay_progress(progress, i+1);\n \t}\n@@ -804,6 +819,7 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)\n \n static void final(const char *final_pack_name, const char *curr_pack_name,\n \t\t  const char *final_index_name, const char *curr_index_name,\n+\t\t  const char *final_mds_name, const char *curr_mds_name,\n \t\t  const char *keep_name, const char *keep_msg,\n \t\t  unsigned char *sha1)\n {\n@@ -866,6 +882,18 @@ static void final(const char *final_pack_name, const char *curr_pack_name,\n \t} else\n \t\tchmod(final_index_name, 0444);\n \n+\tif (final_mds_name != curr_mds_name) {\n+\t\tif (!final_mds_name) {\n+\t\t\tsnprintf(name, sizeof(name), \"%s/pack/pack-%s.mds\",\n+\t\t\t\t get_object_directory(), sha1_to_hex(sha1));\n+\t\t\tfinal_mds_name = name;\n+\t\t}\n+\t\tif (move_temp_to_file(curr_mds_name, final_mds_name))\n+\t\t\tdie(\"cannot store mds file\");\n+\t} else\n+\t\tchmod(final_mds_name, 0444);\n+\n+\n \tif (!from_stdin) {\n \t\tprintf(\"%s\\n\", sha1_to_hex(sha1));\n \t} else {\n@@ -972,18 +1000,46 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)\n \tfree(p);\n }\n \n-static void show_pack_info(int stat_only)\n+static void show_pack_info(int stat, int stat_only, int show_mds,\n+\t\t\t   int mds_file_exists, const char *path)\n {\n \tint i, baseobjects = nr_objects - nr_deltas;\n \tunsigned long *chain_histogram = NULL;\n+\tvoid *data = NULL;\n+\tsize_t mds_size = 0;\n+\tstruct packed_git pg;\n+\n+\tif (mds_file_exists) {\n+\t\tint fd = git_open_noatime(path);\n+\t\tsize_t required_size = 0;\n+\t\tstruct stat st;\n+\t\tif (fd >= 0) {\n+\t\t\tif (fstat(fd, &st)) {\n+\t\t\t\tclose(fd);\n+\t\t\t} else {\n+\t\t\t\tmds_size = xsize_t(st.st_size);\n+\t\t\t\tdata = xmmap(NULL, mds_size,\n+\t\t\t\t\t\tPROT_READ, MAP_PRIVATE, fd, 0);\n+\t\t\t\tclose(fd);\n+\t\t\t\trequired_size = required_git_packed_mds_size\n+\t\t\t\t\t(path, data, nr_objects, mds_size);\n+\t\t\t\tif (required_size == 0) {\n+\t\t\t\t\tmunmap(data, mds_size);\n+\t\t\t\t\tdata = NULL;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif (data == NULL) mds_file_exists = 0;\n+\t\tpg.mds_data = data;\n+\t}\n \n-\tif (deepest_delta)\n+\tif (stat && deepest_delta)\n \t\tchain_histogram = xcalloc(deepest_delta, sizeof(unsigned long));\n \n \tfor (i = 0; i < nr_objects; i++) {\n \t\tstruct object_entry *obj = &objects[i];\n \n-\t\tif (is_delta_type(obj->type))\n+\t\tif (chain_histogram && is_delta_type(obj->type))\n \t\t\tchain_histogram[obj->delta_depth - 1]++;\n \t\tif (stat_only)\n \t\t\tcontinue;\n@@ -992,12 +1048,41 @@ static void show_pack_info(int stat_only)\n \t\t       typename(obj->real_type), obj->size,\n \t\t       (unsigned long)(obj[1].idx.offset - obj->idx.offset),\n \t\t       (uintmax_t)obj->idx.offset);\n+\t\tif (show_mds) {\n+\t\t\tif (mds_file_exists) {\n+\t\t\t\tmdigest_t digest;\n+\t\t\t\tint has_digest = nth_packed_object_mdigest\n+\t\t\t\t\t(&pg, i, &digest);\n+\t\t\t\tif (has_digest) {\n+\t\t\t\t\tprintf(\" md=%s\",\n+\t\t\t\t\t       mdigest_to_external_hex\n+\t\t\t\t\t       (&digest));\n+\t\t\t\t\tif (obj->idx.has_digest) {\n+\t\t\t\t\t\tif (mdigest_tst\n+\t\t\t\t\t\t    (&digest,\n+\t\t\t\t\t\t     &(obj->idx.digest))) {\n+\t\t\t\t\t\t\tprintf\n+\t\t\t\t\t\t\t(\" (should be %s) \",\n+\t\t\t\t\t\t\t mdigest_to_external_hex\n+\t\t\t\t\t\t\t (&(obj->idx.digest)));\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t} else {\n+\t\t\t\t\tprintf(\" <no md>      \");\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tprintf(\" <no md>      \");\n+\t\t\t}\n+\t\t}\n \t\tif (is_delta_type(obj->type)) {\n \t\t\tstruct object_entry *bobj = &objects[obj->base_object_no];\n \t\t\tprintf(\" %u %s\", obj->delta_depth, sha1_to_hex(bobj->idx.sha1));\n \t\t}\n \t\tputchar('\\n');\n \t}\n+\tif (data) munmap(data, mds_size);\n+\tif (!stat)\n+\t\treturn;\n \n \tif (baseobjects)\n \t\tprintf(\"non delta: %d object%s\\n\",\n@@ -1015,10 +1100,12 @@ static void show_pack_info(int stat_only)\n int cmd_index_pack(int argc, const char **argv, const char *prefix)\n {\n \tint i, fix_thin_pack = 0, verify = 0, stat_only = 0, stat = 0;\n-\tconst char *curr_pack, *curr_index;\n-\tconst char *index_name = NULL, *pack_name = NULL;\n+\tint show_mds = 0;\n+\tconst char *curr_pack, *curr_index, *curr_mds;\n+\tconst char *index_name = NULL, *pack_name = NULL, *mds_name = NULL;;\n \tconst char *keep_name = NULL, *keep_msg = NULL;\n \tchar *index_name_buf = NULL, *keep_name_buf = NULL;\n+\tchar *mds_name_buf = NULL;\n \tstruct pack_idx_entry **idx_objects;\n \tstruct pack_idx_option opts;\n \tunsigned char pack_sha1[20];\n@@ -1052,6 +1139,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\tverify = 1;\n \t\t\t\tstat = 1;\n \t\t\t\tstat_only = 1;\n+\t\t\t} else if (!strcmp(arg, \"-M\") ||\n+\t\t\t\t   !strcmp(arg, \"--show-mds\")) {\n+\t\t\t\tverify = 1;\n+\t\t\t\tshow_mds = 1;\n \t\t\t} else if (!strcmp(arg, \"--keep\")) {\n \t\t\t\tkeep_msg = \"\";\n \t\t\t} else if (!prefixcmp(arg, \"--keep=\")) {\n@@ -1075,6 +1166,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\tif (index_name || (i+1) >= argc)\n \t\t\t\t\tusage(index_pack_usage);\n \t\t\t\tindex_name = argv[++i];\n+\t\t\t} else if (!strcmp(arg, \"-m\")) {\n+\t\t\t\tif (mds_name || (i+1) >= argc)\n+\t\t\t\t\tusage(index_pack_usage);\n+\t\t\t\tmds_name = argv[++i];\n \t\t\t} else if (!prefixcmp(arg, \"--index-version=\")) {\n \t\t\t\tchar *c;\n \t\t\t\topts.version = strtoul(arg + 16, &c, 10);\n@@ -1108,6 +1203,16 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \t\tstrcpy(index_name_buf + len - 5, \".idx\");\n \t\tindex_name = index_name_buf;\n \t}\n+\tif (!mds_name && pack_name) {\n+\t\tint len = strlen(pack_name);\n+\t\tif (!has_extension(pack_name, \".pack\"))\n+\t\t\tdie(\"packfile name '%s' does not end with '.pack'\",\n+\t\t\t    pack_name);\n+\t\tmds_name_buf = xmalloc(len);\n+\t\tmemcpy(mds_name_buf, pack_name, len - 5);\n+\t\tstrcpy(mds_name_buf + len - 5, \".mds\");\n+\t\tmds_name = mds_name_buf;\n+\t}\n \tif (keep_msg && !keep_name && pack_name) {\n \t\tint len = strlen(pack_name);\n \t\tif (!has_extension(pack_name, \".pack\"))\n@@ -1170,24 +1275,34 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)\n \tif (strict)\n \t\tcheck_objects();\n \n-\tif (stat)\n-\t\tshow_pack_info(stat_only);\n+\tif (stat || show_mds) {\n+\t\tint mds_file_exists = !access(mds_name, R_OK);\n+\t\tif (mds_file_exists && show_mds) {\n+\t\t  qsort (objects, nr_objects, sizeof (struct object_entry),\n+\t\t\t sha1_compare);\n+\t\t}\n+\t\tshow_pack_info(stat, stat_only, show_mds, mds_file_exists,\n+\t\t\t       mds_name);\n+\t}\n \n \tidx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));\n \tfor (i = 0; i < nr_objects; i++)\n \t\tidx_objects[i] = &objects[i].idx;\n \tcurr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);\n+\tcurr_mds = write_mds_file(mds_name, idx_objects, nr_objects, &opts,pack_sha1);\n \tfree(idx_objects);\n \n \tif (!verify)\n \t\tfinal(pack_name, curr_pack,\n \t\t      index_name, curr_index,\n+\t\t      mds_name, curr_mds,\n \t\t      keep_name, keep_msg,\n \t\t      pack_sha1);\n \telse\n \t\tclose(input_fd);\n \tfree(objects);\n \tfree(index_name_buf);\n+\tfree(mds_name_buf);\n \tfree(keep_name_buf);\n \tif (pack_name == NULL)\n \t\tfree((void *) curr_pack);\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 96c1680..ccfe824 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -17,6 +17,7 @@\n #include \"progress.h\"\n #include \"refs.h\"\n #include \"thread-utils.h\"\n+#include \"mdsdb.h\"\n \n static const char pack_usage[] =\n   \"git pack-objects [ -q | --progress | --all-progress ]\\n\"\n@@ -560,6 +561,8 @@ static struct object_entry **compute_write_order(void)\n \t\tobjects[i].filled = 0;\n \t\tobjects[i].delta_child = NULL;\n \t\tobjects[i].delta_sibling = NULL;\n+\t\tobjects[i].idx.has_digest = 0;\n+\t\tmdigest_clear(&objects[i].idx.digest);\n \t}\n \n \t/*\n@@ -684,8 +687,28 @@ static void write_pack_file(void)\n \n \t\tif (!pack_to_stdout) {\n \t\t\tstruct stat st;\n+#if 1\n \t\t\tchar tmpname[PATH_MAX];\n \n+#else\n+\t\t\tconst char *idx_tmp_name;\n+\t\t\tconst char *mds_tmp_name;\n+\t\t\tchar tmpname[PATH_MAX];\n+\n+\t\t\tidx_tmp_name = write_idx_file(NULL, written_list, nr_written,\n+\t\t\t\t\t\t      &pack_idx_opts, sha1);\n+\t\t\tmds_tmp_name = write_mds_file(NULL, written_list, nr_written,\n+\t\t\t\t\t\t      &pack_idx_opts, sha1);\n+\n+\t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.pack\",\n+\t\t\t\t base_name, sha1_to_hex(sha1));\n+\t\t\tfree_pack_by_name(tmpname);\n+\t\t\tif (adjust_shared_perm(pack_tmp_name))\n+\t\t\t\tdie_errno(\"unable to make temporary pack file readable\");\n+\t\t\tif (rename(pack_tmp_name, tmpname))\n+\t\t\t\tdie_errno(\"unable to rename temporary pack file\");\n+#endif\n+\n \t\t\t/*\n \t\t\t * Packs are runtime accessed in their mtime\n \t\t\t * order since newer packs are more likely to contain\n@@ -707,6 +730,7 @@ static void write_pack_file(void)\n \t\t\t\t\t\ttmpname, strerror(errno));\n \t\t\t}\n \n+#if 1\n \t\t\t/* Enough space for \"-<sha-1>.pack\"? */\n \t\t\tif (sizeof(tmpname) <= strlen(base_name) + 50)\n \t\t\t\tdie(\"pack base name '%s' too long\", base_name);\n@@ -714,6 +738,25 @@ static void write_pack_file(void)\n \t\t\tfinish_tmp_packfile(tmpname, pack_tmp_name,\n \t\t\t\t\t    written_list, nr_written,\n \t\t\t\t\t    &pack_idx_opts, sha1);\n+#else\n+\t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.idx\",\n+\t\t\t\t base_name, sha1_to_hex(sha1));\n+\t\t\tif (adjust_shared_perm(idx_tmp_name))\n+\t\t\t\tdie_errno(\"unable to make temporary index file readable\");\n+\t\t\tif (rename(idx_tmp_name, tmpname))\n+\t\t\t\tdie_errno(\"unable to rename temporary index file\");\n+\n+\t\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.mds\",\n+\t\t\t\t base_name, sha1_to_hex(sha1));\n+\t\t\tif (adjust_shared_perm(mds_tmp_name))\n+\t\t\t\tdie_errno(\"unable to make temporary mds file readable\");\n+\t\t\tif (rename(mds_tmp_name, tmpname))\n+\t\t\t\tdie_errno(\"unable to rename temporary mds file\");\n+\n+\n+\t\t\tfree((void *) idx_tmp_name);\n+\t\t\tfree((void *) mds_tmp_name);\n+#endif\n \t\t\tfree(pack_tmp_name);\n \t\t\tputs(sha1_to_hex(sha1));\n \t\t}\n@@ -830,6 +873,8 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,\n \toff_t found_offset = 0;\n \tint ix;\n \tunsigned hash = name_hash(name);\n+\tint hasdigest;\n+\tmdigest_t digest;\n \n \tix = nr_objects ? locate_object_entry_hash(sha1) : -1;\n \tif (ix >= 0) {\n@@ -846,7 +891,11 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,\n \t\treturn 0;\n \n \tfor (p = packed_git; p; p = p->next) {\n-\t\toff_t offset = find_pack_entry_one(sha1, p);\n+\t\toff_t offset;\n+\t\thasdigest = 0;\n+\t\tmdigest_clear(&digest);\n+\t\toffset = find_pack_entry_one_extended(sha1, p,\n+\t\t\t\t\t\t   &hasdigest, &digest);\n \t\tif (offset) {\n \t\t\tif (!found_pack) {\n \t\t\t\tif (!is_pack_valid(p)) {\n@@ -874,7 +923,37 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,\n \n \tentry = objects + nr_objects++;\n \tmemset(entry, 0, sizeof(*entry));\n+\tif (hasdigest == 0) {\n+\t\t/*\n+\t\t * We pick up MDs for local objects (we already checked the\n+\t\t * pack files).  If that doesn't work, we compute it from\n+\t\t * scratch (which should occur rarely if at all).\n+\t\t */\n+\t\tmdsdb_open(NULL);\n+\t\tswitch (mdsdb_lookup(NULL, sha1, &digest)) {\n+\t\tcase 1:\n+\t\t\thasdigest = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\thasdigest = 0;\n+\t\t}\n+\t\tmdsdb_close(NULL);\n+\t\tif (!hasdigest) {\n+\t\t  enum object_type type;\n+\t\t  unsigned long size;\n+\t\t  unsigned char sbuf[20];\n+\t\t  void *buf = read_sha1_file(sha1, &type, &size);\n+\t\t  if (buf) {\n+\t\t\tconst char *stype = typename(type);\n+\t\t\thash_sha1_file_extended(buf, size, stype, sbuf,\n+\t\t\t\t\t\t&digest);\n+\t\t\thasdigest = 1;\n+\t\t  }\n+\t\t}\n+\t}\n \thashcpy(entry->idx.sha1, sha1);\n+\tentry->idx.has_digest = hasdigest;\n+\tentry->idx.digest = digest;\n \tentry->hash = hash;\n \tif (type)\n \t\tentry->type = type;\ndiff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c\nindex f5c6afc..c09397c 100644\n--- a/builtin/pack-redundant.c\n+++ b/builtin/pack-redundant.c\n@@ -6,6 +6,7 @@\n *\n */\n \n+#include <unistd.h>\n #include \"builtin.h\"\n \n #define BLKSIZE 512\n@@ -682,9 +683,16 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)\n \t}\n \tpl = red = pack_list_difference(local_packs, min);\n \twhile (pl) {\n-\t\tprintf(\"%s\\n%s\\n\",\n-\t\t       sha1_pack_index_name(pl->pack->sha1),\n-\t\t       pl->pack->pack_name);\n+\t\tchar *mdsfile = sha1_pack_mds_name(pl->pack->sha1);\n+\t\tif (!access(mdsfile, F_OK)) {\n+\t\t  printf(\"%s\\n%s\\n%s\\n\", mdsfile,\n+\t\t\t       sha1_pack_index_name(pl->pack->sha1),\n+\t\t\t       pl->pack->pack_name);\n+\t\t} else {\n+\t\t\tprintf(\"%s\\n%s\\n\",\n+\t\t\t       sha1_pack_index_name(pl->pack->sha1),\n+\t\t\t       pl->pack->pack_name);\n+\t\t}\n \t\tpl = pl->next;\n \t}\n \tif (verbose)\ndiff --git a/builtin/prune-packed.c b/builtin/prune-packed.c\nindex f9463de..ec5dfe8 100644\n--- a/builtin/prune-packed.c\n+++ b/builtin/prune-packed.c\n@@ -43,8 +43,11 @@ void prune_packed_objects(int opts)\n {\n \tint i;\n \tstatic char pathname[PATH_MAX];\n+\tstatic char mds_pathname[PATH_MAX];\n \tconst char *dir = get_object_directory();\n+\tconst char *mdsdir = get_object_mds_directory();\n \tint len = strlen(dir);\n+\tint mdslen = strlen(mdsdir);\n \n \tif (opts == VERBOSE)\n \t\tprogress = start_progress_delay(\"Removing duplicate objects\",\n@@ -55,16 +58,26 @@ void prune_packed_objects(int opts)\n \tmemcpy(pathname, dir, len);\n \tif (len && pathname[len-1] != '/')\n \t\tpathname[len++] = '/';\n+\tmemcpy(mds_pathname, mdsdir, mdslen);\n+\tif (mdslen && mds_pathname[mdslen-1] != '/')\n+\t\tmds_pathname[mdslen++] = '/';\n \tfor (i = 0; i < 256; i++) {\n \t\tDIR *d;\n+\t\tDIR *mds_d;\n \n \t\tdisplay_progress(progress, i + 1);\n \t\tsprintf(pathname + len, \"%02x/\", i);\n \t\td = opendir(pathname);\n-\t\tif (!d)\n-\t\t\tcontinue;\n-\t\tprune_dir(i, d, pathname, len + 3, opts);\n-\t\tclosedir(d);\n+\t\tsprintf(mds_pathname + len, \"%02x/\", i);\n+\t\tmds_d = opendir(mds_pathname);\n+\t\tif (d) {\n+\t\t\tprune_dir(i, d, pathname, len + 3, opts);\n+\t\t\tclosedir(d);\n+\t\t}\n+\t\tif (mds_d) {\n+\t\t\tprune_dir(i, mds_d, mds_pathname, mdslen + 3, opts);\n+\t\t\tclosedir(mds_d);\n+\t\t}\n \t}\n \tstop_progress(&progress);\n }\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 58d7cb8..25dde51 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -165,6 +165,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \tmark_reachable_objects(&revs, 1, progress);\n \tstop_progress(&progress);\n \tprune_object_dir(get_object_directory());\n+\tprune_object_dir(get_object_mds_directory());\n \n \tprune_packed_objects(show_only);\n \tremove_temporary_files(get_object_directory());\ndiff --git a/builtin/verify-pack.c b/builtin/verify-pack.c\nindex e841b4a..b94a11e 100644\n--- a/builtin/verify-pack.c\n+++ b/builtin/verify-pack.c\n@@ -5,14 +5,16 @@\n \n #define VERIFY_PACK_VERBOSE 01\n #define VERIFY_PACK_STAT_ONLY 02\n+#define SHOW_MDS 04\n \n static int verify_one_pack(const char *path, unsigned int flags)\n {\n \tstruct child_process index_pack;\n-\tconst char *argv[] = {\"index-pack\", NULL, NULL, NULL };\n+\tconst char *argv[] = {\"index-pack\", NULL, NULL, NULL, NULL };\n \tstruct strbuf arg = STRBUF_INIT;\n \tint verbose = flags & VERIFY_PACK_VERBOSE;\n \tint stat_only = flags & VERIFY_PACK_STAT_ONLY;\n+\tint show_mds = ((flags & SHOW_MDS) != 0)  && !stat_only;\n \tint err;\n \n \tif (stat_only)\n@@ -22,6 +24,8 @@ static int verify_one_pack(const char *path, unsigned int flags)\n \telse\n \t\targv[1] = \"--verify\";\n \n+\tif (show_mds) argv[2] = \"-M\";\n+\n \t/*\n \t * In addition to \"foo.pack\" we accept \"foo.idx\" and \"foo\";\n \t * normalize these forms to \"foo.pack\" for \"index-pack --verify\".\n@@ -31,7 +35,7 @@ static int verify_one_pack(const char *path, unsigned int flags)\n \t\tstrbuf_splice(&arg, arg.len - 3, 3, \"pack\", 4);\n \telse if (!has_extension(arg.buf, \".pack\"))\n \t\tstrbuf_add(&arg, \".pack\", 5);\n-\targv[2] = arg.buf;\n+\targv[2 + show_mds] = arg.buf;\n \n \tmemset(&index_pack, 0, sizeof(index_pack));\n \tindex_pack.argv = argv;\n@@ -46,6 +50,10 @@ static int verify_one_pack(const char *path, unsigned int flags)\n \t\t\tif (!stat_only)\n \t\t\t\tprintf(\"%s: ok\\n\", arg.buf);\n \t\t}\n+\t} else if (show_mds) {\n+\t\tprintf(\"%s: listed (%s)\\n-----------------\\n\", arg.buf,\n+\t\t       (err? \"bad\": \"ok\"));\n+\n \t}\n \tstrbuf_release(&arg);\n \n@@ -67,6 +75,8 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix)\n \t\t\tVERIFY_PACK_VERBOSE),\n \t\tOPT_BIT('s', \"stat-only\", &flags, \"show statistics only\",\n \t\t\tVERIFY_PACK_STAT_ONLY),\n+\t\tOPT_BIT('M', \"show-mds\", &flags, \"show message digests / CRCs\",\n+\t\t\tSHOW_MDS),\n \t\tOPT_END()\n \t};\n \ndiff --git a/fast-import.c b/fast-import.c\nindex 4b9c4b7..f672a76 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -165,6 +165,11 @@ Format of STDIN stream:\n #include \"exec_cmd.h\"\n #include \"dir.h\"\n \n+#ifdef PACKDB\n+#include \"packdb.h\"\n+#endif\n+\n+\n #define PACK_ID_BITS 16\n #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)\n #define DEPTH_BITS 13\n@@ -558,6 +563,8 @@ static struct object_entry *new_object(unsigned char *sha1)\n \n \te = blocks->next_free++;\n \thashcpy(e->idx.sha1, sha1);\n+\te->idx.has_digest = 0;\n+\tmdigest_clear(&e->idx.digest);\n \treturn e;\n }\n \n@@ -904,9 +911,34 @@ static const char *create_index(void)\n \treturn tmpfile;\n }\n \n-static char *keep_pack(const char *curr_index_name)\n+static const char *create_mds(void)\n+{\n+\tconst char *tmpfile;\n+\tstruct pack_idx_entry **mds, **c, **last;\n+\tstruct object_entry *e;\n+\tstruct object_entry_pool *o;\n+\n+\t/* Build the table of object IDs. */\n+\tmds = xmalloc(object_count * sizeof(*mds));\n+\tc = mds;\n+\tfor (o = blocks; o; o = o->next_pool)\n+\t\tfor (e = o->next_free; e-- != o->entries;)\n+\t\t\tif (pack_id == e->pack_id)\n+\t\t\t\t*c++ = &e->idx;\n+\tlast = mds + object_count;\n+\tif (c != last)\n+\t\tdie(\"internal consistency error creating the mds file\");\n+\n+\ttmpfile = write_mds_file(NULL, mds, object_count, &pack_idx_opts, pack_data->sha1);\n+\tfree(mds);\n+\treturn tmpfile;\n+}\n+\n+\n+static char *keep_pack(const char *curr_index_name, const char *curr_mds_name)\n {\n \tstatic char name[PATH_MAX];\n+\tstatic char rname[PATH_MAX];\n \tstatic const char *keep_msg = \"fast-import\";\n \tint keep_fd;\n \n@@ -927,6 +959,13 @@ static char *keep_pack(const char *curr_index_name)\n \tif (move_temp_to_file(curr_index_name, name))\n \t\tdie(\"cannot store index file\");\n \tfree((void *)curr_index_name);\n+\n+\tsnprintf(rname, sizeof(rname), \"%s/pack/pack-%s.mds\",\n+\t\t get_object_directory(), sha1_to_hex(pack_data->sha1));\n+\tif (move_temp_to_file(curr_mds_name, rname))\n+\t\tdie(\"cannot store index file\");\n+\tfree((void *)curr_mds_name);\n+\n \treturn name;\n }\n \n@@ -951,6 +990,7 @@ static void end_packfile(void)\n \tif (object_count) {\n \t\tunsigned char cur_pack_sha1[20];\n \t\tchar *idx_name;\n+\t\tconst char *n1, *n2;\n \t\tint i;\n \t\tstruct branch *b;\n \t\tstruct tag *t;\n@@ -961,7 +1001,9 @@ static void end_packfile(void)\n \t\t\t\t    pack_data->pack_name, object_count,\n \t\t\t\t    cur_pack_sha1, pack_size);\n \t\tclose(pack_data->pack_fd);\n-\t\tidx_name = keep_pack(create_index());\n+\t\tn1 = create_index();\n+\t\tn2 = create_mds();\n+\t\tidx_name = keep_pack(n1, n2);\n \n \t\t/* Register the packfile with core git's machinery. */\n \t\tnew_p = add_packed_git(idx_name, strlen(idx_name), 1);\n@@ -1021,6 +1063,8 @@ static int store_object(\n \tunsigned long hdrlen, deltalen;\n \tgit_SHA_CTX c;\n \tgit_zstream s;\n+\tmdigest_t digest;\n+\tmdigest_context_t mdc;\n \n \thdrlen = sprintf((char *)hdr,\"%s %lu\", typename(type),\n \t\t(unsigned long)dat->len) + 1;\n@@ -1028,10 +1072,28 @@ static int store_object(\n \tgit_SHA1_Update(&c, hdr, hdrlen);\n \tgit_SHA1_Update(&c, dat->buf, dat->len);\n \tgit_SHA1_Final(sha1, &c);\n+\tmdigest_Init(&mdc, MDIGEST_DEFAULT);\n+\tmdigest_Update(&mdc, (unsigned char *)(dat->buf), dat->len);\n+\tmdigest_Final(&digest, &mdc);\n+\n+\tif (has_sha1_file(sha1)) {\n+\t\tmdigest_t old_digest;\n+\t\tif (has_sha1_file_digest(sha1, &old_digest)) {\n+\t\t  if (mdigest_tst(&digest,&old_digest)) {\n+\t\t\t\tdie(\"hash collision on %s [fast-import]\",\n+\t\t\t\t    sha1_to_hex(sha1));\n+\t\t\t}\n+\t\t}\n+\t}\n \tif (sha1out)\n \t\thashcpy(sha1out, sha1);\n \n \te = insert_object(sha1);\n+\te->idx.has_digest = 1;\n+\te->idx.digest = digest;\n+#ifdef PACKDB\n+\tpackdb_process(sha1, &digest);\n+#endif\n \tif (mark)\n \t\tinsert_mark(mark, e);\n \tif (e->idx.offset) {\n@@ -1157,6 +1219,8 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)\n \tunsigned char *out_buf = xmalloc(out_sz);\n \tstruct object_entry *e;\n \tunsigned char sha1[20];\n+\tmdigest_t digest;\n+\tmdigest_context_t mdc;\n \tunsigned long hdrlen;\n \toff_t offset;\n \tgit_SHA_CTX c;\n@@ -1177,6 +1241,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)\n \t\tdie(\"impossibly large object header\");\n \n \tgit_SHA1_Init(&c);\n+\tmdigest_Init(&mdc, MDIGEST_DEFAULT);\n \tgit_SHA1_Update(&c, out_buf, hdrlen);\n \n \tcrc32_begin(pack_file);\n@@ -1199,6 +1264,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)\n \t\t\t\tdie(\"EOF in data (%\" PRIuMAX \" bytes remaining)\", len);\n \n \t\t\tgit_SHA1_Update(&c, in_buf, n);\n+\t\t\tmdigest_Update(&mdc, in_buf, n);\n \t\t\ts.next_in = in_buf;\n \t\t\ts.avail_in = n;\n \t\t\tlen -= n;\n@@ -1225,11 +1291,14 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)\n \t}\n \tgit_deflate_end(&s);\n \tgit_SHA1_Final(sha1, &c);\n+\tmdigest_Final(&digest, &mdc);\n \n \tif (sha1out)\n \t\thashcpy(sha1out, sha1);\n \n \te = insert_object(sha1);\n+\te->idx.has_digest = 1;\n+\te->idx.digest =  digest;\n \n \tif (mark)\n \t\tinsert_mark(mark, e);\n@@ -1828,6 +1897,8 @@ static void read_marks(void)\n \t\t\tif (type < 0)\n \t\t\t\tdie(\"object not found: %s\", sha1_to_hex(sha1));\n \t\t\te = insert_object(sha1);\n+\t\t\te->idx.has_digest =\n+\t\t\t\thas_sha1_file_digest(sha1, &e->idx.digest);\n \t\t\te->type = type;\n \t\t\te->pack_id = MAX_PACK_ID;\n \t\t\te->idx.offset = 1; /* just not zero! */\n@@ -2896,6 +2967,8 @@ static struct object_entry *dereference(struct object_entry *oe,\n \t\t\tdie(\"object not found: %s\", sha1_to_hex(sha1));\n \t\t/* cache it! */\n \t\toe = insert_object(sha1);\n+\t\toe->idx.has_digest =\n+\t\t\thas_sha1_file_digest(sha1, &oe->idx.digest);\n \t\toe->type = type;\n \t\toe->pack_id = MAX_PACK_ID;\n \t\toe->idx.offset = 1;\ndiff --git a/git-repack.sh b/git-repack.sh\nindex 624feec..7602853 100755\n--- a/git-repack.sh\n+++ b/git-repack.sh\n@@ -91,6 +91,7 @@ if [ -z \"$names\" ]; then\n \tsay Nothing new to pack.\n fi\n \n+\n # Ok we have prepared all new packfiles.\n \n # First see if there are packs of the same name and if so\n@@ -100,7 +101,7 @@ rollback=\n failed=\n for name in $names\n do\n-\tfor sfx in pack idx\n+\tfor sfx in pack idx mds\n \tdo\n \t\tfile=pack-$name.$sfx\n \t\ttest -f \"$PACKDIR/$file\" || continue\n@@ -148,15 +149,22 @@ do\n \tfullbases=\"$fullbases pack-$name\"\n \tchmod a-w \"$PACKTMP-$name.pack\"\n \tchmod a-w \"$PACKTMP-$name.idx\"\n+\t(chmod a-w \"$PACKTMP-$name.mds\" 2>/dev/null || exit 0 )\n \tmv -f \"$PACKTMP-$name.pack\" \"$PACKDIR/pack-$name.pack\" &&\n \tmv -f \"$PACKTMP-$name.idx\"  \"$PACKDIR/pack-$name.idx\" ||\n \texit\n+\tif test -f \"$PACKTMP-$name.mds\"\n+\tthen\n+\t\tmv -f \"$PACKTMP-$name.mds\"  \"$PACKDIR/pack-$name.mds\" \\\n+\t\t    2>/dev/null || exit\n+\tfi\n done\n \n # Remove the \"old-\" files\n for name in $names\n do\n \trm -f \"$PACKDIR/old-pack-$name.idx\"\n+\trm -f \"$PACKDIR/old-pack-$name.mds\"\n \trm -f \"$PACKDIR/old-pack-$name.pack\"\n done\n \n@@ -172,7 +180,7 @@ then\n \t\t  do\n \t\t\tcase \" $fullbases \" in\n \t\t\t*\" $e \"*) ;;\n-\t\t\t*)\trm -f \"$e.pack\" \"$e.idx\" \"$e.keep\" ;;\n+\t\t\t*)\trm -f \"$e.pack\" \"$e.idx\" \"$e.mds\" \"$e.keep\" ;;\n \t\t\tesac\n \t\t  done\n \t\t)\ndiff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh\nindex 602806d..1b72d46 100755\n--- a/t/t5300-pack-object.sh\n+++ b/t/t5300-pack-object.sh\n@@ -54,7 +54,7 @@ cd \"$TRASH/.git2\"\n \n test_expect_success \\\n     'check unpack without delta' \\\n-    '(cd ../.git && find objects -type f -print) |\n+    '(cd ../.git && find objects -type f  -print) | grep -v mdsd | grep -v packdb |\n      while read path\n      do\n          cmp $path ../.git/$path || {\n@@ -84,7 +84,7 @@ unset GIT_OBJECT_DIRECTORY\n cd \"$TRASH/.git2\"\n test_expect_success \\\n     'check unpack with REF_DELTA' \\\n-    '(cd ../.git && find objects -type f -print) |\n+    '(cd ../.git && find objects -type f -print) | grep -v mdsd | grep -v packdb |\n      while read path\n      do\n          cmp $path ../.git/$path || {\n@@ -114,7 +114,7 @@ unset GIT_OBJECT_DIRECTORY\n cd \"$TRASH/.git2\"\n test_expect_success \\\n     'check unpack with OFS_DELTA' \\\n-    '(cd ../.git && find objects -type f -print) |\n+    '(cd ../.git && find objects -type f -print) | grep -v mdsd | grep -v packdb |\n      while read path\n      do\n          cmp $path ../.git/$path || {\n@@ -211,6 +211,17 @@ test_expect_success \\\n \t\t\ttest-3-${packname_3}.idx'\n \n test_expect_success \\\n+    'verify pack -v -M' \\\n+    'test -z \"`git verify-pack -v -M test-1-${packname_1}.idx \\\n+\t\t\ttest-2-${packname_2}.idx \\\n+\t\t\ttest-3-${packname_3}.idx | grep \\<no\\ md\\>`\" &&\n+     test 0 != `git verify-pack -v -M test-1-${packname_1}.idx | grep md= | wc -l` &&\n+     test -z \"`git verify-pack -v -M test-1-${packname_1}.idx | grep \"should be\"`\" &&\n+     (x=`git verify-pack -v -M test-1-${packname_1}.idx | wc -l`\n+     y=`git verify-pack -v -M test-1-${packname_1}.idx |grep -v \\<no\\ md\\> | wc -l`\n+     test $x = $y)'\n+\n+test_expect_success \\\n     'verify-pack catches mismatched .idx and .pack files' \\\n     'cat test-1-${packname_1}.idx >test-3.idx &&\n      cat test-2-${packname_2}.pack >test-3.pack &&\ndiff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh\nindex 2fc5af6..ec0d72f 100755\n--- a/t/t5301-sliding-window.sh\n+++ b/t/t5301-sliding-window.sh\n@@ -22,13 +22,19 @@ test_expect_success \\\n      git repack -a -d &&\n      test \"`git count-objects`\" = \"0 objects, 0 kilobytes\" &&\n      pack1=`ls .git/objects/pack/*.pack` &&\n-     test -f \"$pack1\"'\n+     test -f \"$pack1\"  &&\n+     test -z \"`git count-objects -v -M | grep MD`\"'\n \n test_expect_success \\\n     'verify-pack -v, defaults' \\\n     'git verify-pack -v \"$pack1\"'\n \n test_expect_success \\\n+    'verify-pack -v -M, defaults' \\\n+    'git verify-pack -v -M \"$pack1\" | grep \"<no md>\" > tmp\n+     test -z \"`cat tmp`\"'\n+\n+test_expect_success \\\n     'verify-pack -v, packedGitWindowSize == 1 page' \\\n     'git config core.packedGitWindowSize 512 &&\n      git verify-pack -v \"$pack1\"'\n@@ -49,12 +55,14 @@ test_expect_success \\\n      test \"`git count-objects`\" = \"0 objects, 0 kilobytes\" &&\n      pack2=`ls .git/objects/pack/*.pack` &&\n      test -f \"$pack2\" &&\n-     test \"$pack1\" \\!= \"$pack2\"'\n+     test \"$pack1\" \\!= \"$pack2\" &&\n+     test -z \"`git count-objects -v -M | grep MD`\"'\n \n test_expect_success \\\n     'verify-pack -v, defaults' \\\n     'git config --unset core.packedGitWindowSize &&\n      git config --unset core.packedGitLimit &&\n-     git verify-pack -v \"$pack2\"'\n+     git verify-pack -v \"$pack2\" &&\n+     test -z \"`git count-objects -v -M | grep MD`\"'\n \n test_done\ndiff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh\nindex f8fa924..da10200 100755\n--- a/t/t5302-pack-index.sh\n+++ b/t/t5302-pack-index.sh\n@@ -37,12 +37,14 @@ test_expect_success \\\n test_expect_success \\\n     'pack-objects with index version 1' \\\n     'pack1=$(git pack-objects --index-version=1 test-1 <obj-list) &&\n-     git verify-pack -v \"test-1-${pack1}.pack\"'\n+     git verify-pack -v \"test-1-${pack1}.pack\" &&\n+     test -z \"`git count-objects -v -M | grep MD`\"'\n \n test_expect_success \\\n     'pack-objects with index version 2' \\\n     'pack2=$(git pack-objects --index-version=2 test-2 <obj-list) &&\n-     git verify-pack -v \"test-2-${pack2}.pack\"'\n+     git verify-pack -v \"test-2-${pack2}.pack\" &&\n+     test -z \"`git count-objects -v -M | grep MD`\"'\n \n test_expect_success \\\n     'both packs should be identical' \\\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex d645328..86075a7 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -37,7 +37,8 @@ test_expect_success 'prune stale packs' '\n \tgit prune --expire 1.day &&\n \ttest -f $orig_pack &&\n \ttest -f .git/objects/tmp_2.pack &&\n-\t! test -f .git/objects/tmp_1.pack\n+\t! test -f .git/objects/tmp_1.pack  &&\n+\ttest -z \"`git count-objects -v -M | grep MD`\"\n \n '\n \n@@ -50,7 +51,8 @@ test_expect_success 'prune --expire' '\n \ttest-chmtime =-86500 $BLOB_FILE &&\n \tgit prune --expire 1.day &&\n \ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n-\t! test -f $BLOB_FILE\n+\t! test -f $BLOB_FILE  &&\n+\ttest -z \"`git count-objects -v -M | grep MD`\"\n \n '\n \n@@ -64,7 +66,8 @@ test_expect_success 'gc: implicit prune --expire' '\n \ttest-chmtime =-$((2*$week+1)) $BLOB_FILE &&\n \tgit gc &&\n \ttest $before = $(git count-objects | sed \"s/ .*//\") &&\n-\t! test -f $BLOB_FILE\n+\t! test -f $BLOB_FILE  &&\n+\ttest -z \"`git count-objects -v -M | grep MD`\"\n \n '\n \n@@ -78,8 +81,8 @@ test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '\n test_expect_success 'gc: start with ok gc.pruneExpire' '\n \n \tgit config gc.pruneExpire 2.days.ago &&\n-\tgit gc\n-\n+\tgit gc &&\n+\ttest -z \"`git count-objects -v -M | grep MD`\"\n '\n \n test_expect_success 'prune: prune nonsense parameters' '\ndiff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh\nindex 438aaf6..63b4a13 100755\n--- a/t/t9300-fast-import.sh\n+++ b/t/t9300-fast-import.sh\n@@ -109,6 +109,12 @@ test_expect_success \\\n \t'A: verify pack' \\\n \t'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'\n \n+test_expect_success \\\n+\t'A: verify pack -v -M --- all objects have CRCs' \\\n+\t'for p in .git/objects/pack/*.pack;\n+\tdo git verify-pack -v -M $p | grep \"<no md>\" > tmp;\n+\t   test -z \"`cat tmp`\" || exit; done'\n+\n cat >expect <<EOF\n author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE\n@@ -1504,7 +1510,7 @@ INPUT_END\n test_expect_success \\\n \t'O: blank lines not necessary after other commands' \\\n \t'git fast-import <input &&\n-\t test 8 = `find .git/objects/pack -type f | wc -l` &&\n+\t test 8 = `find .git/objects/pack -type f | grep -v .mds | wc -l` &&\n \t test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` &&\n \t git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual &&\n \t test_cmp expect actual'\n-- \n1.7.1\n"}]}