Merge branch 'nd/object-allocation-comments' into next
authorJunio C Hamano <gitster@pobox.com>
Thu, 8 Mar 2018 21:34:16 +0000 (13:34 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 8 Mar 2018 21:34:16 +0000 (13:34 -0800)
Code doc update.

* nd/object-allocation-comments:
object.h: realign object flag allocation comment
object.h: update flag allocation comment

1  2 
builtin/index-pack.c
builtin/pack-objects.c
builtin/reflog.c
builtin/unpack-objects.c
object.h
diff --combined builtin/index-pack.c
index 59878e70b8017e1a531f2976230419a57c210038,c7f0184c1b1bfaba9de6e57f4069bf76582b8530..9791d428892f0f96d30ecb22d0ca9cf40e4b9f38
@@@ -49,6 -49,7 +49,7 @@@ struct thread_local 
        int pack_fd;
  };
  
+ /* Remember to update object flag allocation in object.h */
  #define FLAG_LINK (1u<<20)
  #define FLAG_CHECKED (1u<<21)
  
@@@ -91,7 -92,7 +92,7 @@@ static unsigned int input_offset, input
  static off_t consumed_bytes;
  static off_t max_input_size;
  static unsigned deepest_delta;
 -static git_SHA_CTX input_ctx;
 +static git_hash_ctx input_ctx;
  static uint32_t input_crc32;
  static int input_fd, output_fd;
  static const char *curr_pack;
@@@ -228,7 -229,7 +229,7 @@@ static unsigned check_object(struct obj
                if (type != obj->type)
                        die(_("object %s: expected type %s, found %s"),
                            oid_to_hex(&obj->oid),
 -                          typename(obj->type), typename(type));
 +                          type_name(obj->type), type_name(type));
                obj->flags |= FLAG_CHECKED;
                return 1;
        }
@@@ -253,7 -254,7 +254,7 @@@ static void flush(void
        if (input_offset) {
                if (output_fd >= 0)
                        write_or_die(output_fd, input_buffer, input_offset);
 -              git_SHA1_Update(&input_ctx, input_buffer, input_offset);
 +              the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
                memmove(input_buffer, input_buffer + input_offset, input_len);
                input_offset = 0;
        }
@@@ -326,7 -327,7 +327,7 @@@ static const char *open_pack_file(cons
                output_fd = -1;
                nothread_data.pack_fd = input_fd;
        }
 -      git_SHA1_Init(&input_ctx);
 +      the_hash_algo->init_fn(&input_ctx);
        return pack_name;
  }
  
@@@ -437,22 -438,22 +438,22 @@@ static int is_delta_type(enum object_ty
  }
  
  static void *unpack_entry_data(off_t offset, unsigned long size,
 -                             enum object_type type, unsigned char *sha1)
 +                             enum object_type type, struct object_id *oid)
  {
        static char fixed_buf[8192];
        int status;
        git_zstream stream;
        void *buf;
 -      git_SHA_CTX c;
 +      git_hash_ctx c;
        char hdr[32];
        int hdrlen;
  
        if (!is_delta_type(type)) {
 -              hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), size) + 1;
 -              git_SHA1_Init(&c);
 -              git_SHA1_Update(&c, hdr, hdrlen);
 +              hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), size) + 1;
 +              the_hash_algo->init_fn(&c);
 +              the_hash_algo->update_fn(&c, hdr, hdrlen);
        } else
 -              sha1 = NULL;
 +              oid = NULL;
        if (type == OBJ_BLOB && size > big_file_threshold)
                buf = fixed_buf;
        else
                stream.avail_in = input_len;
                status = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
 -              if (sha1)
 -                      git_SHA1_Update(&c, last_out, stream.next_out - last_out);
 +              if (oid)
 +                      the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
                if (buf == fixed_buf) {
                        stream.next_out = buf;
                        stream.avail_out = sizeof(fixed_buf);
        if (stream.total_out != size || status != Z_STREAM_END)
                bad_object(offset, _("inflate returned %d"), status);
        git_inflate_end(&stream);
 -      if (sha1)
 -              git_SHA1_Final(sha1, &c);
 +      if (oid)
 +              the_hash_algo->final_fn(oid->hash, &c);
        return buf == fixed_buf ? NULL : buf;
  }
  
  static void *unpack_raw_entry(struct object_entry *obj,
                              off_t *ofs_offset,
 -                            unsigned char *ref_sha1,
 -                            unsigned char *sha1)
 +                            struct object_id *ref_oid,
 +                            struct object_id *oid)
  {
        unsigned char *p;
        unsigned long size, c;
  
        switch (obj->type) {
        case OBJ_REF_DELTA:
 -              hashcpy(ref_sha1, fill(20));
 -              use(20);
 +              hashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));
 +              use(the_hash_algo->rawsz);
                break;
        case OBJ_OFS_DELTA:
                p = fill(1);
        }
        obj->hdr_size = consumed_bytes - obj->idx.offset;
  
 -      data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
 +      data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, oid);
        obj->idx.crc32 = input_crc32;
        return data;
  }
@@@ -849,7 -850,7 +850,7 @@@ static void sha1_object(const void *dat
                        obj = parse_object_buffer(oid, type, size, buf,
                                                  &eaten);
                        if (!obj)
 -                              die(_("invalid %s"), typename(type));
 +                              die(_("invalid %s"), type_name(type));
                        if (do_fsck_object &&
                            fsck_object(obj, buf, size, &fsck_options))
                                die(_("Error in object"));
@@@ -958,8 -959,9 +959,8 @@@ static void resolve_delta(struct object
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
 -      hash_sha1_file(result->data, result->size,
 -                     typename(delta_obj->real_type),
 -                     delta_obj->idx.oid.hash);
 +      hash_object_file(result->data, result->size,
 +                       type_name(delta_obj->real_type), &delta_obj->idx.oid);
        sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    &delta_obj->idx.oid);
        counter_lock();
@@@ -1118,11 -1120,11 +1119,11 @@@ static void *threaded_second_pass(void 
   * - calculate SHA1 of all non-delta objects;
   * - remember base (SHA1 or offset) for all deltas.
   */
 -static void parse_pack_objects(unsigned char *sha1)
 +static void parse_pack_objects(unsigned char *hash)
  {
        int i, nr_delays = 0;
        struct ofs_delta_entry *ofs_delta = ofs_deltas;
 -      unsigned char ref_delta_sha1[20];
 +      struct object_id ref_delta_oid;
        struct stat st;
  
        if (verbose)
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
                void *data = unpack_raw_entry(obj, &ofs_delta->offset,
 -                                            ref_delta_sha1,
 -                                            obj->idx.oid.hash);
 +                                            &ref_delta_oid,
 +                                            &obj->idx.oid);
                obj->real_type = obj->type;
                if (obj->type == OBJ_OFS_DELTA) {
                        nr_ofs_deltas++;
                        ofs_delta++;
                } else if (obj->type == OBJ_REF_DELTA) {
                        ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
 -                      hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1);
 +                      hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_oid.hash);
                        ref_deltas[nr_ref_deltas].obj_no = i;
                        nr_ref_deltas++;
                } else if (!data) {
  
        /* Check pack integrity */
        flush();
 -      git_SHA1_Final(sha1, &input_ctx);
 -      if (hashcmp(fill(20), sha1))
 +      the_hash_algo->final_fn(hash, &input_ctx);
 +      if (hashcmp(fill(the_hash_algo->rawsz), hash))
                die(_("pack is corrupted (SHA1 mismatch)"));
 -      use(20);
 +      use(the_hash_algo->rawsz);
  
        /* If input_fd is a file, we should have reached its end now. */
        if (fstat(input_fd, &st))
@@@ -1238,21 -1240,21 +1239,21 @@@ static void resolve_deltas(void
  /*
   * Third pass:
   * - append objects to convert thin pack to full pack if required
 - * - write the final 20-byte SHA-1
 + * - write the final pack hash
   */
 -static void fix_unresolved_deltas(struct sha1file *f);
 -static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
 +static void fix_unresolved_deltas(struct hashfile *f);
 +static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_hash)
  {
        if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
                stop_progress(&progress);
 -              /* Flush remaining pack final 20-byte SHA1. */
 +              /* Flush remaining pack final hash. */
                flush();
                return;
        }
  
        if (fix_thin_pack) {
 -              struct sha1file *f;
 -              unsigned char read_sha1[20], tail_sha1[20];
 +              struct hashfile *f;
 +              unsigned char read_hash[GIT_MAX_RAWSZ], tail_hash[GIT_MAX_RAWSZ];
                struct strbuf msg = STRBUF_INIT;
                int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
                int nr_objects_initial = nr_objects;
                REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
                memset(objects + nr_objects + 1, 0,
                       nr_unresolved * sizeof(*objects));
 -              f = sha1fd(output_fd, curr_pack);
 +              f = hashfd(output_fd, curr_pack);
                fix_unresolved_deltas(f);
                strbuf_addf(&msg, Q_("completed with %d local object",
                                     "completed with %d local objects",
                            nr_objects - nr_objects_initial);
                stop_progress_msg(&progress, msg.buf);
                strbuf_release(&msg);
 -              sha1close(f, tail_sha1, 0);
 -              hashcpy(read_sha1, pack_sha1);
 -              fixup_pack_header_footer(output_fd, pack_sha1,
 +              hashclose(f, tail_hash, 0);
 +              hashcpy(read_hash, pack_hash);
 +              fixup_pack_header_footer(output_fd, pack_hash,
                                         curr_pack, nr_objects,
 -                                       read_sha1, consumed_bytes-20);
 -              if (hashcmp(read_sha1, tail_sha1) != 0)
 +                                       read_hash, consumed_bytes-the_hash_algo->rawsz);
 +              if (hashcmp(read_hash, tail_hash) != 0)
                        die(_("Unexpected tail checksum for %s "
                              "(disk corruption?)"), curr_pack);
        }
                    nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
  }
  
 -static int write_compressed(struct sha1file *f, void *in, unsigned int size)
 +static int write_compressed(struct hashfile *f, void *in, unsigned int size)
  {
        git_zstream stream;
        int status;
                stream.next_out = outbuf;
                stream.avail_out = sizeof(outbuf);
                status = git_deflate(&stream, Z_FINISH);
 -              sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
 +              hashwrite(f, outbuf, sizeof(outbuf) - stream.avail_out);
        } while (status == Z_OK);
  
        if (status != Z_STREAM_END)
        return size;
  }
  
 -static struct object_entry *append_obj_to_pack(struct sha1file *f,
 +static struct object_entry *append_obj_to_pack(struct hashfile *f,
                               const unsigned char *sha1, void *buf,
                               unsigned long size, enum object_type type)
  {
        }
        header[n++] = c;
        crc32_begin(f);
 -      sha1write(f, header, n);
 +      hashwrite(f, header, n);
        obj[0].size = size;
        obj[0].hdr_size = n;
        obj[0].type = type;
        obj[1].idx.offset = obj[0].idx.offset + n;
        obj[1].idx.offset += write_compressed(f, buf, size);
        obj[0].idx.crc32 = crc32_end(f);
 -      sha1flush(f);
 +      hashflush(f);
        hashcpy(obj->idx.oid.hash, sha1);
        return obj;
  }
@@@ -1346,7 -1348,7 +1347,7 @@@ static int delta_pos_compare(const voi
        return a->obj_no - b->obj_no;
  }
  
 -static void fix_unresolved_deltas(struct sha1file *f)
 +static void fix_unresolved_deltas(struct hashfile *f)
  {
        struct ref_delta_entry **sorted_by_pos;
        int i;
                        continue;
  
                if (check_sha1_signature(d->sha1, base_obj->data,
 -                              base_obj->size, typename(type)))
 +                              base_obj->size, type_name(type)))
                        die(_("local object %s is corrupt"), sha1_to_hex(d->sha1));
                base_obj->obj = append_obj_to_pack(f, d->sha1,
                                        base_obj->data, base_obj->size, type);
        free(sorted_by_pos);
  }
  
 +static const char *derive_filename(const char *pack_name, const char *suffix,
 +                                 struct strbuf *buf)
 +{
 +      size_t len;
 +      if (!strip_suffix(pack_name, ".pack", &len))
 +              die(_("packfile name '%s' does not end with '.pack'"),
 +                  pack_name);
 +      strbuf_add(buf, pack_name, len);
 +      strbuf_addch(buf, '.');
 +      strbuf_addstr(buf, suffix);
 +      return buf->buf;
 +}
 +
 +static void write_special_file(const char *suffix, const char *msg,
 +                             const char *pack_name, const unsigned char *hash,
 +                             const char **report)
 +{
 +      struct strbuf name_buf = STRBUF_INIT;
 +      const char *filename;
 +      int fd;
 +      int msg_len = strlen(msg);
 +
 +      if (pack_name)
 +              filename = derive_filename(pack_name, suffix, &name_buf);
 +      else
 +              filename = odb_pack_name(&name_buf, hash, suffix);
 +
 +      fd = odb_pack_keep(filename);
 +      if (fd < 0) {
 +              if (errno != EEXIST)
 +                      die_errno(_("cannot write %s file '%s'"),
 +                                suffix, filename);
 +      } else {
 +              if (msg_len > 0) {
 +                      write_or_die(fd, msg, msg_len);
 +                      write_or_die(fd, "\n", 1);
 +              }
 +              if (close(fd) != 0)
 +                      die_errno(_("cannot close written %s file '%s'"),
 +                                suffix, filename);
 +              if (report)
 +                      *report = suffix;
 +      }
 +      strbuf_release(&name_buf);
 +}
 +
  static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
 -                const char *keep_name, const char *keep_msg,
 -                unsigned char *sha1)
 +                const char *keep_msg, const char *promisor_msg,
 +                unsigned char *hash)
  {
        const char *report = "pack";
        struct strbuf pack_name = STRBUF_INIT;
        struct strbuf index_name = STRBUF_INIT;
 -      struct strbuf keep_name_buf = STRBUF_INIT;
        int err;
  
        if (!from_stdin) {
                        die_errno(_("error while closing pack file"));
        }
  
 -      if (keep_msg) {
 -              int keep_fd, keep_msg_len = strlen(keep_msg);
 -
 -              if (!keep_name)
 -                      keep_name = odb_pack_name(&keep_name_buf, sha1, "keep");
 -
 -              keep_fd = odb_pack_keep(keep_name);
 -              if (keep_fd < 0) {
 -                      if (errno != EEXIST)
 -                              die_errno(_("cannot write keep file '%s'"),
 -                                        keep_name);
 -              } else {
 -                      if (keep_msg_len > 0) {
 -                              write_or_die(keep_fd, keep_msg, keep_msg_len);
 -                              write_or_die(keep_fd, "\n", 1);
 -                      }
 -                      if (close(keep_fd) != 0)
 -                              die_errno(_("cannot close written keep file '%s'"),
 -                                        keep_name);
 -                      report = "keep";
 -              }
 -      }
 +      if (keep_msg)
 +              write_special_file("keep", keep_msg, final_pack_name, hash,
 +                                 &report);
 +      if (promisor_msg)
 +              write_special_file("promisor", promisor_msg, final_pack_name,
 +                                 hash, NULL);
  
        if (final_pack_name != curr_pack_name) {
                if (!final_pack_name)
 -                      final_pack_name = odb_pack_name(&pack_name, sha1, "pack");
 +                      final_pack_name = odb_pack_name(&pack_name, hash, "pack");
                if (finalize_object_file(curr_pack_name, final_pack_name))
                        die(_("cannot store pack file"));
        } else if (from_stdin)
  
        if (final_index_name != curr_index_name) {
                if (!final_index_name)
 -                      final_index_name = odb_pack_name(&index_name, sha1, "idx");
 +                      final_index_name = odb_pack_name(&index_name, hash, "idx");
                if (finalize_object_file(curr_index_name, final_index_name))
                        die(_("cannot store index file"));
        } else
                chmod(final_index_name, 0444);
  
        if (!from_stdin) {
 -              printf("%s\n", sha1_to_hex(sha1));
 +              printf("%s\n", sha1_to_hex(hash));
        } else {
                struct strbuf buf = STRBUF_INIT;
  
 -              strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1));
 +              strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(hash));
                write_or_die(1, buf.buf, buf.len);
                strbuf_release(&buf);
  
  
        strbuf_release(&index_name);
        strbuf_release(&pack_name);
 -      strbuf_release(&keep_name_buf);
  }
  
  static int git_index_pack_config(const char *k, const char *v, void *cb)
@@@ -1615,7 -1589,7 +1616,7 @@@ static void show_pack_info(int stat_onl
                        continue;
                printf("%s %-6s %lu %lu %"PRIuMAX,
                       oid_to_hex(&obj->idx.oid),
 -                     typename(obj->real_type), obj->size,
 +                     type_name(obj->real_type), obj->size,
                       (unsigned long)(obj[1].idx.offset - obj->idx.offset),
                       (uintmax_t)obj->idx.offset);
                if (is_delta_type(obj->type)) {
        }
  }
  
 -static const char *derive_filename(const char *pack_name, const char *suffix,
 -                                 struct strbuf *buf)
 -{
 -      size_t len;
 -      if (!strip_suffix(pack_name, ".pack", &len))
 -              die(_("packfile name '%s' does not end with '.pack'"),
 -                  pack_name);
 -      strbuf_add(buf, pack_name, len);
 -      strbuf_addstr(buf, suffix);
 -      return buf->buf;
 -}
 -
  int cmd_index_pack(int argc, const char **argv, const char *prefix)
  {
        int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
        const char *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
 -      const char *keep_name = NULL, *keep_msg = NULL;
 -      struct strbuf index_name_buf = STRBUF_INIT,
 -                    keep_name_buf = STRBUF_INIT;
 +      const char *keep_msg = NULL;
 +      const char *promisor_msg = NULL;
 +      struct strbuf index_name_buf = STRBUF_INIT;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
 -      unsigned char pack_sha1[20];
 +      unsigned char pack_hash[GIT_MAX_RAWSZ];
        unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
        int report_end_of_input = 0;
  
 +      /*
 +       * index-pack never needs to fetch missing objects, since it only
 +       * accesses the repo to do hash collision checks
 +       */
 +      fetch_if_missing = 0;
 +
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
  
                                stat_only = 1;
                        } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
                                ; /* nothing to do */
 +                      } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
 +                              ; /* already parsed */
                        } else if (starts_with(arg, "--threads=")) {
                                char *end;
                                nr_threads = strtoul(arg+10, &end, 0);
        if (from_stdin && !startup_info->have_repository)
                die(_("--stdin requires a git repository"));
        if (!index_name && pack_name)
 -              index_name = derive_filename(pack_name, ".idx", &index_name_buf);
 -      if (keep_msg && !keep_name && pack_name)
 -              keep_name = derive_filename(pack_name, ".keep", &keep_name_buf);
 +              index_name = derive_filename(pack_name, "idx", &index_name_buf);
  
        if (verify) {
                if (!index_name)
        if (show_stat)
                obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
        ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
 -      parse_pack_objects(pack_sha1);
 +      parse_pack_objects(pack_hash);
        if (report_end_of_input)
                write_in_full(2, "\0", 1);
        resolve_deltas();
 -      conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
 +      conclude_pack(fix_thin_pack, curr_pack, pack_hash);
        free(ofs_deltas);
        free(ref_deltas);
        if (strict)
        ALLOC_ARRAY(idx_objects, nr_objects);
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;
 -      curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
 +      curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
        free(idx_objects);
  
        if (!verify)
                final(pack_name, curr_pack,
                      index_name, curr_index,
 -                    keep_name, keep_msg,
 -                    pack_sha1);
 +                    keep_msg, promisor_msg,
 +                    pack_hash);
        else
                close(input_fd);
        free(objects);
        strbuf_release(&index_name_buf);
 -      strbuf_release(&keep_name_buf);
        if (pack_name == NULL)
                free((void *) curr_pack);
        if (index_name == NULL)
diff --combined builtin/pack-objects.c
index a197926eaa697b45d4583cd4bea71f4a3059960e,9c3e69e0634c6ebf8170ed17eb1f002a329ae5eb..e9d3cfb9e33a6b874751ac6acc5aac2361d4a58d
@@@ -26,7 -26,7 +26,7 @@@
  #include "reachable.h"
  #include "sha1-array.h"
  #include "argv-array.h"
 -#include "mru.h"
 +#include "list.h"
  #include "packfile.h"
  
  static const char *pack_usage[] = {
@@@ -75,8 -75,6 +75,8 @@@ static int use_bitmap_index = -1
  static int write_bitmap_index;
  static uint16_t write_bitmap_options;
  
 +static int exclude_promisor_objects;
 +
  static unsigned long delta_cache_size = 0;
  static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
  static unsigned long cache_max_small_delta_size = 1000;
@@@ -86,9 -84,8 +86,9 @@@ static unsigned long window_memory_limi
  static struct list_objects_filter_options filter_options;
  
  enum missing_action {
 -      MA_ERROR = 0,    /* fail if any missing objects are encountered */
 -      MA_ALLOW_ANY,    /* silently allow ALL missing objects */
 +      MA_ERROR = 0,      /* fail if any missing objects are encountered */
 +      MA_ALLOW_ANY,      /* silently allow ALL missing objects */
 +      MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
  };
  static enum missing_action arg_missing_action;
  static show_object_fn fn_show_object;
@@@ -164,7 -161,7 +164,7 @@@ static unsigned long do_compress(void *
        return stream.total_out;
  }
  
 -static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
 +static unsigned long write_large_blob_data(struct git_istream *st, struct hashfile *f,
                                           const struct object_id *oid)
  {
        git_zstream stream;
                        stream.next_out = obuf;
                        stream.avail_out = sizeof(obuf);
                        zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
 -                      sha1write(f, obuf, stream.next_out - obuf);
 +                      hashwrite(f, obuf, stream.next_out - obuf);
                        olen += stream.next_out - obuf;
                }
                if (stream.avail_in)
@@@ -233,7 -230,7 +233,7 @@@ static int check_pack_inflate(struct pa
                stream.total_in == len) ? 0 : -1;
  }
  
 -static void copy_pack_data(struct sha1file *f,
 +static void copy_pack_data(struct hashfile *f,
                struct packed_git *p,
                struct pack_window **w_curs,
                off_t offset,
                in = use_pack(p, w_curs, offset, &avail);
                if (avail > len)
                        avail = (unsigned long)len;
 -              sha1write(f, in, avail);
 +              hashwrite(f, in, avail);
                offset += avail;
                len -= avail;
        }
  }
  
  /* Return 0 if we will bust the pack-size limit */
 -static unsigned long write_no_reuse_object(struct sha1file *f, struct object_entry *entry,
 +static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
                                           unsigned long limit, int usable_delta)
  {
        unsigned long size, datalen;
                        free(buf);
                        return 0;
                }
 -              sha1write(f, header, hdrlen);
 -              sha1write(f, dheader + pos, sizeof(dheader) - pos);
 +              hashwrite(f, header, hdrlen);
 +              hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
        } else if (type == OBJ_REF_DELTA) {
                /*
                        free(buf);
                        return 0;
                }
 -              sha1write(f, header, hdrlen);
 -              sha1write(f, entry->delta->idx.oid.hash, 20);
 +              hashwrite(f, header, hdrlen);
 +              hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
                        free(buf);
                        return 0;
                }
 -              sha1write(f, header, hdrlen);
 +              hashwrite(f, header, hdrlen);
        }
        if (st) {
                datalen = write_large_blob_data(st, f, &entry->idx.oid);
                close_istream(st);
        } else {
 -              sha1write(f, buf, datalen);
 +              hashwrite(f, buf, datalen);
                free(buf);
        }
  
  }
  
  /* Return 0 if we will bust the pack-size limit */
 -static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
 +static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
                                unsigned long limit, int usable_delta)
  {
        struct packed_git *p = entry->in_pack;
                        unuse_pack(&w_curs);
                        return 0;
                }
 -              sha1write(f, header, hdrlen);
 -              sha1write(f, dheader + pos, sizeof(dheader) - pos);
 +              hashwrite(f, header, hdrlen);
 +              hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
                reused_delta++;
        } else if (type == OBJ_REF_DELTA) {
                        unuse_pack(&w_curs);
                        return 0;
                }
 -              sha1write(f, header, hdrlen);
 -              sha1write(f, entry->delta->idx.oid.hash, 20);
 +              hashwrite(f, header, hdrlen);
 +              hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
                reused_delta++;
        } else {
                        unuse_pack(&w_curs);
                        return 0;
                }
 -              sha1write(f, header, hdrlen);
 +              hashwrite(f, header, hdrlen);
        }
        copy_pack_data(f, p, &w_curs, offset, datalen);
        unuse_pack(&w_curs);
  }
  
  /* Return 0 if we will bust the pack-size limit */
 -static off_t write_object(struct sha1file *f,
 +static off_t write_object(struct hashfile *f,
                          struct object_entry *entry,
                          off_t write_offset)
  {
@@@ -515,7 -512,7 +515,7 @@@ enum write_one_status 
        WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
  };
  
 -static enum write_one_status write_one(struct sha1file *f,
 +static enum write_one_status write_one(struct hashfile *f,
                                       struct object_entry *e,
                                       off_t *offset)
  {
@@@ -734,7 -731,7 +734,7 @@@ static struct object_entry **compute_wr
        return wo;
  }
  
 -static off_t write_reused_pack(struct sha1file *f)
 +static off_t write_reused_pack(struct hashfile *f)
  {
        unsigned char buffer[8192];
        off_t to_write, total;
                if (read_pack > to_write)
                        read_pack = to_write;
  
 -              sha1write(f, buffer, read_pack);
 +              hashwrite(f, buffer, read_pack);
                to_write -= read_pack;
  
                /*
@@@ -794,7 -791,7 +794,7 @@@ static const char no_split_warning[] = 
  static void write_pack_file(void)
  {
        uint32_t i = 0, j;
 -      struct sha1file *f;
 +      struct hashfile *f;
        off_t offset;
        uint32_t nr_remaining = nr_result;
        time_t last_mtime = 0;
                char *pack_tmp_name = NULL;
  
                if (pack_to_stdout)
 -                      f = sha1fd_throughput(1, "<stdout>", progress_state);
 +                      f = hashfd_throughput(1, "<stdout>", progress_state);
                else
                        f = create_tmp_packfile(&pack_tmp_name);
  
                 * If so, rewrite it like in fast-import
                 */
                if (pack_to_stdout) {
 -                      sha1close(f, oid.hash, CSUM_CLOSE);
 +                      hashclose(f, oid.hash, CSUM_CLOSE);
                } else if (nr_written == nr_remaining) {
 -                      sha1close(f, oid.hash, CSUM_FSYNC);
 +                      hashclose(f, oid.hash, CSUM_FSYNC);
                } else {
 -                      int fd = sha1close(f, oid.hash, 0);
 +                      int fd = hashclose(f, oid.hash, 0);
                        fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
                                                 nr_written, oid.hash, offset);
                        close(fd);
@@@ -1009,8 -1006,8 +1009,8 @@@ static int want_object_in_pack(const st
                               struct packed_git **found_pack,
                               off_t *found_offset)
  {
 -      struct mru_entry *entry;
        int want;
 +      struct list_head *pos;
  
        if (!exclude && local && has_loose_object_nonlocal(oid->hash))
                return 0;
                        return want;
        }
  
 -      for (entry = packed_git_mru.head; entry; entry = entry->next) {
 -              struct packed_git *p = entry->item;
 +      list_for_each(pos, &packed_git_mru) {
 +              struct packed_git *p = list_entry(pos, struct packed_git, mru);
                off_t offset;
  
                if (p == *found_pack)
                        }
                        want = want_found_object(exclude, p);
                        if (!exclude && want > 0)
 -                              mru_mark(&packed_git_mru, entry);
 +                              list_move(&p->mru, &packed_git_mru);
                        if (want != -1)
                                return want;
                }
@@@ -1379,10 -1376,10 +1379,10 @@@ static void cleanup_preferred_base(void
        it = pbase_tree;
        pbase_tree = NULL;
        while (it) {
 -              struct pbase_tree *this = it;
 -              it = this->next;
 -              free(this->pcache.tree_data);
 -              free(this);
 +              struct pbase_tree *tmp = it;
 +              it = tmp->next;
 +              free(tmp->pcache.tree_data);
 +              free(tmp);
        }
  
        for (i = 0; i < ARRAY_SIZE(pbase_tree_cache); i++) {
@@@ -2549,6 -2546,7 +2549,7 @@@ static void read_object_list_from_stdin
        }
  }
  
+ /* Remember to update object flag allocation in object.h */
  #define OBJECT_ADDED (1u<<20)
  
  static void show_commit(struct commit *commit, void *data)
@@@ -2581,20 -2579,6 +2582,20 @@@ static void show_object__ma_allow_any(s
        show_object(obj, name, data);
  }
  
 +static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
 +{
 +      assert(arg_missing_action == MA_ALLOW_PROMISOR);
 +
 +      /*
 +       * Quietly ignore EXPECTED missing objects.  This avoids problems with
 +       * staging them now and getting an odd error later.
 +       */
 +      if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
 +              return;
 +
 +      show_object(obj, name, data);
 +}
 +
  static int option_parse_missing_action(const struct option *opt,
                                       const char *arg, int unset)
  {
  
        if (!strcmp(arg, "allow-any")) {
                arg_missing_action = MA_ALLOW_ANY;
 +              fetch_if_missing = 0;
                fn_show_object = show_object__ma_allow_any;
                return 0;
        }
  
 +      if (!strcmp(arg, "allow-promisor")) {
 +              arg_missing_action = MA_ALLOW_PROMISOR;
 +              fetch_if_missing = 0;
 +              fn_show_object = show_object__ma_allow_promisor;
 +              return 0;
 +      }
 +
        die(_("invalid value for --missing"));
        return 0;
  }
@@@ -2793,7 -2769,7 +2794,7 @@@ static void loosen_unused_packed_object
                        if (!packlist_find(&to_pack, oid.hash, NULL) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
 -                              if (force_object_loose(oid.hash, p->mtime))
 +                              if (force_object_loose(&oid, p->mtime))
                                        die("unable to force loose object");
                }
        }
@@@ -3034,8 -3010,6 +3035,8 @@@ int cmd_pack_objects(int argc, const ch
                { OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
                  N_("handling for missing objects"), PARSE_OPT_NONEG,
                  option_parse_missing_action },
 +              OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
 +                       N_("do not pack objects in promisor packfiles")),
                OPT_END(),
        };
  
                argv_array_push(&rp, "--unpacked");
        }
  
 +      if (exclude_promisor_objects) {
 +              use_internal_rev_list = 1;
 +              fetch_if_missing = 0;
 +              argv_array_push(&rp, "--exclude-promisor-objects");
 +      }
 +
        if (!reuse_object)
                reuse_delta = 0;
        if (pack_compression_level == -1)
diff --combined builtin/reflog.c
index ac3dcd7a51170cd9146d044f6ab70203e6591507,95becf0e7e26d44173cf880c8c697e50c132578a..4719a5354cf182eb91b257a99da97b9b81da5257
@@@ -52,6 -52,7 +52,7 @@@ struct collect_reflog_cb 
        int nr;
  };
  
+ /* Remember to update object flag allocation in object.h */
  #define INCOMPLETE    (1u<<10)
  #define STUDYING      (1u<<11)
  #define REACHABLE     (1u<<12)
@@@ -289,20 -290,20 +290,20 @@@ static int should_expire_reflog_ent(str
                                    const char *message, void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
 -      struct commit *old, *new;
 +      struct commit *old_commit, *new_commit;
  
        if (timestamp < cb->cmd.expire_total)
                return 1;
  
 -      old = new = NULL;
 +      old_commit = new_commit = NULL;
        if (cb->cmd.stalefix &&
 -          (!keep_entry(&old, ooid) || !keep_entry(&new, noid)))
 +          (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
                return 1;
  
        if (timestamp < cb->cmd.expire_unreachable) {
                if (cb->unreachable_expire_kind == UE_ALWAYS)
                        return 1;
 -              if (unreachable(cb, old, ooid) || unreachable(cb, new, noid))
 +              if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
                        return 1;
        }
  
diff --combined builtin/unpack-objects.c
index 9f96949bc02be374382283cf1f35ac9ec946da2f,b2ad6fba2f03334bef9b230b6f4c899e60615d7f..6620feec68b15573340f4c28fe6be952e3c00e3a
@@@ -21,7 -21,7 +21,7 @@@ static unsigned char buffer[4096]
  static unsigned int offset, len;
  static off_t consumed_bytes;
  static off_t max_input_size;
 -static git_SHA_CTX ctx;
 +static git_hash_ctx ctx;
  static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
  
  /*
@@@ -62,7 -62,7 +62,7 @@@ static void *fill(int min
        if (min > sizeof(buffer))
                die("cannot fill %d bytes", min);
        if (offset) {
 -              git_SHA1_Update(&ctx, buffer, offset);
 +              the_hash_algo->update_fn(&ctx, buffer, offset);
                memmove(buffer, buffer + offset, len);
                offset = 0;
        }
@@@ -158,6 -158,7 +158,7 @@@ struct obj_info 
        struct object *obj;
  };
  
+ /* Remember to update object flag allocation in object.h */
  #define FLAG_OPEN (1u<<20)
  #define FLAG_WRITTEN (1u<<21)
  
@@@ -172,8 -173,7 +173,8 @@@ static void write_cached_object(struct 
  {
        struct object_id oid;
  
 -      if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0)
 +      if (write_object_file(obj_buf->buffer, obj_buf->size,
 +                            type_name(obj->type), &oid) < 0)
                die("failed to write object %s", oid_to_hex(&obj->oid));
        obj->flags |= FLAG_WRITTEN;
  }
@@@ -238,16 -238,14 +239,16 @@@ static void write_object(unsigned nr, e
                         void *buf, unsigned long size)
  {
        if (!strict) {
 -              if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
 +              if (write_object_file(buf, size, type_name(type),
 +                                    &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
                obj_list[nr].obj = NULL;
        } else if (type == OBJ_BLOB) {
                struct blob *blob;
 -              if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
 +              if (write_object_file(buf, size, type_name(type),
 +                                    &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
        } else {
                struct object *obj;
                int eaten;
 -              hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash);
 +              hash_object_file(buf, size, type_name(type), &obj_list[nr].oid);
                added_object(nr, type, buf, size);
                obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
                                          &eaten);
                if (!obj)
 -                      die("invalid %s", typename(type));
 +                      die("invalid %s", type_name(type));
                add_object_buffer(obj, buf, size);
                obj->flags |= FLAG_OPEN;
                obj_list[nr].obj = obj;
@@@ -348,8 -346,8 +349,8 @@@ static void unpack_delta_entry(enum obj
        struct object_id base_oid;
  
        if (type == OBJ_REF_DELTA) {
 -              hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ));
 -              use(GIT_SHA1_RAWSZ);
 +              hashcpy(base_oid.hash, fill(the_hash_algo->rawsz));
 +              use(the_hash_algo->rawsz);
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
                        free(delta_data);
@@@ -567,15 -565,15 +568,15 @@@ int cmd_unpack_objects(int argc, const 
                /* We don't take any non-flag arguments now.. Maybe some day */
                usage(unpack_usage);
        }
 -      git_SHA1_Init(&ctx);
 +      the_hash_algo->init_fn(&ctx);
        unpack_all();
 -      git_SHA1_Update(&ctx, buffer, offset);
 -      git_SHA1_Final(oid.hash, &ctx);
 +      the_hash_algo->update_fn(&ctx, buffer, offset);
 +      the_hash_algo->final_fn(oid.hash, &ctx);
        if (strict)
                write_rest();
 -      if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash))
 +      if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
                die("final sha1 did not match");
 -      use(GIT_SHA1_RAWSZ);
 +      use(the_hash_algo->rawsz);
  
        /* Write the last part of the buffer to stdout */
        while (len) {
diff --combined object.h
index a5eb263808e8f1969a625578a22f33c0aff2ef0a,6f56a8693794661459dce09da0d61482f9130b36..f13f85b2a94e3afc15debfbaf89416b5cda45acb
+++ b/object.h
@@@ -28,18 -28,22 +28,22 @@@ struct object_array 
  #define TYPE_BITS   3
  /*
   * object flag allocation:
-  * revision.h:      0---------10                                26
-  * fetch-pack.c:    0---5
-  * walker.c:        0-2
-  * upload-pack.c:       4       11----------------19
-  * builtin/blame.c:               12-13
-  * bisect.c:                               16
-  * bundle.c:                               16
-  * http-push.c:                            16-----19
-  * commit.c:                               16-----19
-  * sha1_name.c:                                     20
-  * list-objects-filter.c:                             21
-  * builtin/fsck.c:  0--3
+  * revision.h:               0---------10                                26
+  * fetch-pack.c:             0----5
+  * walker.c:                 0-2
+  * upload-pack.c:                4       11----------------19
+  * builtin/blame.c:                        12-13
+  * bisect.c:                                        16
+  * bundle.c:                                        16
+  * http-push.c:                                     16-----19
+  * commit.c:                                        16-----19
+  * sha1_name.c:                                              20
+  * list-objects-filter.c:                                      21
+  * builtin/fsck.c:           0--3
+  * builtin/index-pack.c:                                     2021
+  * builtin/pack-objects.c:                                   20
+  * builtin/reflog.c:                   10--12
+  * builtin/unpack-objects.c:                                 2021
   */
  #define FLAG_BITS  27
  
@@@ -53,7 -57,7 +57,7 @@@ struct object 
        struct object_id oid;
  };
  
 -extern const char *typename(unsigned int type);
 +extern const char *type_name(unsigned int type);
  extern int type_from_string_gently(const char *str, ssize_t, int gentle);
  #define type_from_string(str) type_from_string_gently(str, -1, 0)