cherry: don't set ignored rev_info options
[gitweb.git] / builtin / index-pack.c
index 807ee56f79865cb04376268b051dceda5133f329..953dd3004e285ce7aa0432f4fe0eacb0d0c2c887 100644 (file)
@@ -9,6 +9,7 @@
 #include "progress.h"
 #include "fsck.h"
 #include "exec_cmd.h"
+#include "streaming.h"
 #include "thread-utils.h"
 
 static const char index_pack_usage[] =
@@ -39,8 +40,8 @@ struct base_data {
        int ofs_first, ofs_last;
 };
 
-#if !defined(NO_PTHREADS) && defined(NO_PREAD)
-/* NO_PREAD uses compat/pread.c, which is not thread-safe. Disable threading. */
+#if !defined(NO_PTHREADS) && defined(NO_THREAD_SAFE_PREAD)
+/* pread() emulation is not thread-safe. Disable threading. */
 #define NO_PTHREADS
 #endif
 
@@ -166,7 +167,7 @@ static int mark_link(struct object *obj, int type, void *data)
                return -1;
 
        if (type != OBJ_ANY && obj->type != type)
-               die("object type mismatch at %s", sha1_to_hex(obj->sha1));
+               die(_("object type mismatch at %s"), sha1_to_hex(obj->sha1));
 
        obj->flags |= FLAG_LINK;
        return 0;
@@ -186,7 +187,7 @@ static void check_object(struct object *obj)
                unsigned long size;
                int type = sha1_object_info(obj->sha1, &size);
                if (type != obj->type || type <= 0)
-                       die("object of unexpected type");
+                       die(_("object of unexpected type"));
                obj->flags |= FLAG_CHECKED;
                return;
        }
@@ -223,15 +224,18 @@ static void *fill(int min)
        if (min <= input_len)
                return input_buffer + input_offset;
        if (min > sizeof(input_buffer))
-               die("cannot fill %d bytes", min);
+               die(Q_("cannot fill %d byte",
+                      "cannot fill %d bytes",
+                      min),
+                   min);
        flush();
        do {
                ssize_t ret = xread(input_fd, input_buffer + input_len,
                                sizeof(input_buffer) - input_len);
                if (ret <= 0) {
                        if (!ret)
-                               die("early EOF");
-                       die_errno("read error on input");
+                               die(_("early EOF"));
+                       die_errno(_("read error on input"));
                }
                input_len += ret;
                if (from_stdin)
@@ -243,14 +247,14 @@ static void *fill(int min)
 static void use(int bytes)
 {
        if (bytes > input_len)
-               die("used more bytes than were available");
+               die(_("used more bytes than were available"));
        input_crc32 = crc32(input_crc32, input_buffer + input_offset, bytes);
        input_len -= bytes;
        input_offset += bytes;
 
        /* make sure off_t is sufficiently large not to wrap */
        if (signed_add_overflows(consumed_bytes, bytes))
-               die("pack too large for current definition of off_t");
+               die(_("pack too large for current definition of off_t"));
        consumed_bytes += bytes;
 }
 
@@ -266,12 +270,12 @@ static const char *open_pack_file(const char *pack_name)
                } else
                        output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
                if (output_fd < 0)
-                       die_errno("unable to create '%s'", pack_name);
+                       die_errno(_("unable to create '%s'"), pack_name);
                pack_fd = output_fd;
        } else {
                input_fd = open(pack_name, O_RDONLY);
                if (input_fd < 0)
-                       die_errno("cannot open packfile '%s'", pack_name);
+                       die_errno(_("cannot open packfile '%s'"), pack_name);
                output_fd = -1;
                pack_fd = input_fd;
        }
@@ -285,7 +289,7 @@ static void parse_pack_header(void)
 
        /* Header consistency check */
        if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
-               die("pack signature mismatch");
+               die(_("pack signature mismatch"));
        if (!pack_version_ok(hdr->hdr_version))
                die("pack version %"PRIu32" unsupported",
                        ntohl(hdr->hdr_version));
@@ -305,7 +309,7 @@ static NORETURN void bad_object(unsigned long offset, const char *format, ...)
        va_start(params, format);
        vsnprintf(buf, sizeof(buf), format, params);
        va_end(params);
-       die("pack has bad object at offset %lu: %s", offset, buf);
+       die(_("pack has bad object at offset %lu: %s"), offset, buf);
 }
 
 static inline struct thread_local *get_thread_data(void)
@@ -381,30 +385,62 @@ static void unlink_base_data(struct base_data *c)
        free_base_data(c);
 }
 
-static void *unpack_entry_data(unsigned long offset, unsigned long size)
+static int is_delta_type(enum object_type type)
+{
+       return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+}
+
+static void *unpack_entry_data(unsigned long offset, unsigned long size,
+                              enum object_type type, unsigned char *sha1)
 {
+       static char fixed_buf[8192];
        int status;
        git_zstream stream;
-       void *buf = xmalloc(size);
+       void *buf;
+       git_SHA_CTX c;
+       char hdr[32];
+       int hdrlen;
+
+       if (!is_delta_type(type)) {
+               hdrlen = sprintf(hdr, "%s %lu", typename(type), size) + 1;
+               git_SHA1_Init(&c);
+               git_SHA1_Update(&c, hdr, hdrlen);
+       } else
+               sha1 = NULL;
+       if (type == OBJ_BLOB && size > big_file_threshold)
+               buf = fixed_buf;
+       else
+               buf = xmalloc(size);
 
        memset(&stream, 0, sizeof(stream));
        git_inflate_init(&stream);
        stream.next_out = buf;
-       stream.avail_out = size;
+       stream.avail_out = buf == fixed_buf ? sizeof(fixed_buf) : size;
 
        do {
+               unsigned char *last_out = stream.next_out;
                stream.next_in = fill(1);
                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 (buf == fixed_buf) {
+                       stream.next_out = buf;
+                       stream.avail_out = sizeof(fixed_buf);
+               }
        } while (status == Z_OK);
        if (stream.total_out != size || status != Z_STREAM_END)
-               bad_object(offset, "inflate returned %d", status);
+               bad_object(offset, _("inflate returned %d"), status);
        git_inflate_end(&stream);
-       return buf;
+       if (sha1)
+               git_SHA1_Final(sha1, &c);
+       return buf == fixed_buf ? NULL : buf;
 }
 
-static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
+static void *unpack_raw_entry(struct object_entry *obj,
+                             union delta_base *delta_base,
+                             unsigned char *sha1)
 {
        unsigned char *p;
        unsigned long size, c;
@@ -444,7 +480,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
                while (c & 128) {
                        base_offset += 1;
                        if (!base_offset || MSB(base_offset, 7))
-                               bad_object(obj->idx.offset, "offset value overflow for delta base object");
+                               bad_object(obj->idx.offset, _("offset value overflow for delta base object"));
                        p = fill(1);
                        c = *p;
                        use(1);
@@ -452,7 +488,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
                }
                delta_base->offset = obj->idx.offset - base_offset;
                if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset)
-                       bad_object(obj->idx.offset, "delta base offset is out of bound");
+                       bad_object(obj->idx.offset, _("delta base offset is out of bound"));
                break;
        case OBJ_COMMIT:
        case OBJ_TREE:
@@ -460,16 +496,18 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
        case OBJ_TAG:
                break;
        default:
-               bad_object(obj->idx.offset, "unknown object type %d", obj->type);
+               bad_object(obj->idx.offset, _("unknown object type %d"), obj->type);
        }
        obj->hdr_size = consumed_bytes - obj->idx.offset;
 
-       data = unpack_entry_data(obj->idx.offset, obj->size);
+       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
        obj->idx.crc32 = input_crc32;
        return data;
 }
 
-static void *get_data_from_pack(struct object_entry *obj)
+static void *unpack_data(struct object_entry *obj,
+                        int (*consume)(const unsigned char *, unsigned long, void *),
+                        void *cb_data)
 {
        off_t from = obj[0].idx.offset + obj[0].hdr_size;
        unsigned long len = obj[1].idx.offset - from;
@@ -477,37 +515,62 @@ static void *get_data_from_pack(struct object_entry *obj)
        git_zstream stream;
        int status;
 
-       data = xmalloc(obj->size);
+       data = xmalloc(consume ? 64*1024 : obj->size);
        inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
 
        memset(&stream, 0, sizeof(stream));
        git_inflate_init(&stream);
        stream.next_out = data;
-       stream.avail_out = obj->size;
+       stream.avail_out = consume ? 64*1024 : obj->size;
 
        do {
                ssize_t n = (len < 64*1024) ? len : 64*1024;
                n = pread(pack_fd, inbuf, n, from);
                if (n < 0)
-                       die_errno("cannot pread pack file");
+                       die_errno(_("cannot pread pack file"));
                if (!n)
-                       die("premature end of pack file, %lu bytes missing", len);
+                       die(Q_("premature end of pack file, %lu byte missing",
+                              "premature end of pack file, %lu bytes missing",
+                              len),
+                           len);
                from += n;
                len -= n;
                stream.next_in = inbuf;
                stream.avail_in = n;
-               status = git_inflate(&stream, 0);
+               if (!consume)
+                       status = git_inflate(&stream, 0);
+               else {
+                       do {
+                               status = git_inflate(&stream, 0);
+                               if (consume(data, stream.next_out - data, cb_data)) {
+                                       free(inbuf);
+                                       free(data);
+                                       return NULL;
+                               }
+                               stream.next_out = data;
+                               stream.avail_out = 64*1024;
+                       } while (status == Z_OK && stream.avail_in);
+               }
        } while (len && status == Z_OK && !stream.avail_in);
 
        /* This has been inflated OK when first encountered, so... */
        if (status != Z_STREAM_END || stream.total_out != obj->size)
-               die("serious inflate inconsistency");
+               die(_("serious inflate inconsistency"));
 
        git_inflate_end(&stream);
        free(inbuf);
+       if (consume) {
+               free(data);
+               data = NULL;
+       }
        return data;
 }
 
+static void *get_data_from_pack(struct object_entry *obj)
+{
+       return unpack_data(obj, NULL, NULL);
+}
+
 static int compare_delta_bases(const union delta_base *base1,
                               const union delta_base *base2,
                               enum object_type type1,
@@ -562,25 +625,102 @@ static void find_delta_children(const union delta_base *base,
        *last_index = last;
 }
 
-static void sha1_object(const void *data, unsigned long size,
-                       enum object_type type, unsigned char *sha1)
+struct compare_data {
+       struct object_entry *entry;
+       struct git_istream *st;
+       unsigned char *buf;
+       unsigned long buf_size;
+};
+
+static int compare_objects(const unsigned char *buf, unsigned long size,
+                          void *cb_data)
 {
-       hash_sha1_file(data, size, typename(type), sha1);
+       struct compare_data *data = cb_data;
+
+       if (data->buf_size < size) {
+               free(data->buf);
+               data->buf = xmalloc(size);
+               data->buf_size = size;
+       }
+
+       while (size) {
+               ssize_t len = read_istream(data->st, data->buf, size);
+               if (len == 0)
+                       die(_("SHA1 COLLISION FOUND WITH %s !"),
+                           sha1_to_hex(data->entry->idx.sha1));
+               if (len < 0)
+                       die(_("unable to read %s"),
+                           sha1_to_hex(data->entry->idx.sha1));
+               if (memcmp(buf, data->buf, len))
+                       die(_("SHA1 COLLISION FOUND WITH %s !"),
+                           sha1_to_hex(data->entry->idx.sha1));
+               size -= len;
+               buf += len;
+       }
+       return 0;
+}
+
+static int check_collison(struct object_entry *entry)
+{
+       struct compare_data data;
+       enum object_type type;
+       unsigned long size;
+
+       if (entry->size <= big_file_threshold || entry->type != OBJ_BLOB)
+               return -1;
+
+       memset(&data, 0, sizeof(data));
+       data.entry = entry;
+       data.st = open_istream(entry->idx.sha1, &type, &size, NULL);
+       if (!data.st)
+               return -1;
+       if (size != entry->size || type != entry->type)
+               die(_("SHA1 COLLISION FOUND WITH %s !"),
+                   sha1_to_hex(entry->idx.sha1));
+       unpack_data(entry, compare_objects, &data);
+       close_istream(data.st);
+       free(data.buf);
+       return 0;
+}
+
+static void sha1_object(const void *data, struct object_entry *obj_entry,
+                       unsigned long size, enum object_type type,
+                       const unsigned char *sha1)
+{
+       void *new_data = NULL;
+       int collision_test_needed;
+
+       assert(data || obj_entry);
+
        read_lock();
-       if (has_sha1_file(sha1)) {
+       collision_test_needed = has_sha1_file(sha1);
+       read_unlock();
+
+       if (collision_test_needed && !data) {
+               read_lock();
+               if (!check_collison(obj_entry))
+                       collision_test_needed = 0;
+               read_unlock();
+       }
+       if (collision_test_needed) {
                void *has_data;
                enum object_type has_type;
                unsigned long has_size;
+               read_lock();
+               has_type = sha1_object_info(sha1, &has_size);
+               if (has_type != type || has_size != size)
+                       die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
                has_data = read_sha1_file(sha1, &has_type, &has_size);
                read_unlock();
+               if (!data)
+                       data = new_data = get_data_from_pack(obj_entry);
                if (!has_data)
-                       die("cannot read existing object %s", sha1_to_hex(sha1));
+                       die(_("cannot read existing object %s"), sha1_to_hex(sha1));
                if (size != has_size || type != has_type ||
                    memcmp(data, has_data, size) != 0)
-                       die("SHA1 COLLISION FOUND WITH %s !", sha1_to_hex(sha1));
+                       die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
                free(has_data);
-       } else
-               read_unlock();
+       }
 
        if (strict) {
                read_lock();
@@ -589,23 +729,26 @@ static void sha1_object(const void *data, unsigned long size,
                        if (blob)
                                blob->object.flags |= FLAG_CHECKED;
                        else
-                               die("invalid blob object %s", sha1_to_hex(sha1));
+                               die(_("invalid blob object %s"), sha1_to_hex(sha1));
                } else {
                        struct object *obj;
                        int eaten;
                        void *buf = (void *) data;
 
+                       if (!buf)
+                               buf = new_data = get_data_from_pack(obj_entry);
+
                        /*
                         * we do not need to free the memory here, as the
                         * buf is deleted by the caller.
                         */
                        obj = parse_object_buffer(sha1, type, size, buf, &eaten);
                        if (!obj)
-                               die("invalid %s", typename(type));
+                               die(_("invalid %s"), typename(type));
                        if (fsck_object(obj, 1, fsck_error_function))
-                               die("Error in object");
+                               die(_("Error in object"));
                        if (fsck_walk(obj, mark_link, NULL))
-                               die("Not all child objects of %s are reachable", sha1_to_hex(obj->sha1));
+                               die(_("Not all child objects of %s are reachable"), sha1_to_hex(obj->sha1));
 
                        if (obj->type == OBJ_TREE) {
                                struct tree *item = (struct tree *) obj;
@@ -619,11 +762,8 @@ static void sha1_object(const void *data, unsigned long size,
                }
                read_unlock();
        }
-}
 
-static int is_delta_type(enum object_type type)
-{
-       return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+       free(new_data);
 }
 
 /*
@@ -678,7 +818,7 @@ static void *get_base_data(struct base_data *c)
                                &c->size);
                        free(raw);
                        if (!c->data)
-                               bad_object(obj->idx.offset, "failed to apply delta");
+                               bad_object(obj->idx.offset, _("failed to apply delta"));
                        get_thread_data()->base_cache_used += c->size;
                        prune_base_data(c);
                }
@@ -704,8 +844,10 @@ static void resolve_delta(struct object_entry *delta_obj,
                                   delta_data, delta_obj->size, &result->size);
        free(delta_data);
        if (!result->data)
-               bad_object(delta_obj->idx.offset, "failed to apply delta");
-       sha1_object(result->data, result->size, delta_obj->real_type,
+               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.sha1);
+       sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    delta_obj->idx.sha1);
        counter_lock();
        nr_resolved_deltas++;
@@ -835,24 +977,28 @@ static void *threaded_second_pass(void *data)
  */
 static void parse_pack_objects(unsigned char *sha1)
 {
-       int i;
+       int i, nr_delays = 0;
        struct delta_entry *delta = deltas;
        struct stat st;
 
        if (verbose)
                progress = start_progress(
-                               from_stdin ? "Receiving objects" : "Indexing objects",
+                               from_stdin ? _("Receiving objects") : _("Indexing objects"),
                                nr_objects);
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
-               void *data = unpack_raw_entry(obj, &delta->base);
+               void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1);
                obj->real_type = obj->type;
                if (is_delta_type(obj->type)) {
                        nr_deltas++;
                        delta->obj_no = i;
                        delta++;
+               } else if (!data) {
+                       /* large blobs, check later */
+                       obj->real_type = OBJ_BAD;
+                       nr_delays++;
                } else
-                       sha1_object(data, obj->size, obj->type, obj->idx.sha1);
+                       sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1);
                free(data);
                display_progress(progress, i+1);
        }
@@ -863,15 +1009,26 @@ static void parse_pack_objects(unsigned char *sha1)
        flush();
        git_SHA1_Final(sha1, &input_ctx);
        if (hashcmp(fill(20), sha1))
-               die("pack is corrupted (SHA1 mismatch)");
+               die(_("pack is corrupted (SHA1 mismatch)"));
        use(20);
 
        /* If input_fd is a file, we should have reached its end now. */
        if (fstat(input_fd, &st))
-               die_errno("cannot fstat packfile");
+               die_errno(_("cannot fstat packfile"));
        if (S_ISREG(st.st_mode) &&
                        lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
-               die("pack has junk at the end");
+               die(_("pack has junk at the end"));
+
+       for (i = 0; i < nr_objects; i++) {
+               struct object_entry *obj = &objects[i];
+               if (obj->real_type != OBJ_BAD)
+                       continue;
+               obj->real_type = obj->type;
+               sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1);
+               nr_delays--;
+       }
+       if (nr_delays)
+               die(_("confusion beyond insanity in parse_pack_objects()"));
 }
 
 /*
@@ -894,7 +1051,7 @@ static void resolve_deltas(void)
              compare_delta_entry);
 
        if (verbose)
-               progress = start_progress("Resolving deltas", nr_deltas);
+               progress = start_progress(_("Resolving deltas"), nr_deltas);
 
 #ifndef NO_PTHREADS
        nr_dispatched = 0;
@@ -945,7 +1102,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                int nr_unresolved = nr_deltas - nr_resolved_deltas;
                int nr_objects_initial = nr_objects;
                if (nr_unresolved <= 0)
-                       die("confusion beyond insanity");
+                       die(_("confusion beyond insanity"));
                objects = xrealloc(objects,
                                   (nr_objects + nr_unresolved + 1)
                                   * sizeof(*objects));
@@ -964,7 +1121,9 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                            "(disk corruption?)", curr_pack);
        }
        if (nr_deltas != nr_resolved_deltas)
-               die("pack has %d unresolved deltas",
+               die(Q_("pack has %d unresolved delta",
+                      "pack has %d unresolved deltas",
+                      nr_deltas - nr_resolved_deltas),
                    nr_deltas - nr_resolved_deltas);
 }
 
@@ -987,7 +1146,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
        } while (status == Z_OK);
 
        if (status != Z_STREAM_END)
-               die("unable to deflate appended object (%d)", status);
+               die(_("unable to deflate appended object (%d)"), status);
        size = stream.total_out;
        git_deflate_end(&stream);
        return size;
@@ -1066,7 +1225,7 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
 
                if (check_sha1_signature(d->base.sha1, base_obj->data,
                                base_obj->size, typename(type)))
-                       die("local object %s is corrupt", sha1_to_hex(d->base.sha1));
+                       die(_("local object %s is corrupt"), sha1_to_hex(d->base.sha1));
                base_obj->obj = append_obj_to_pack(f, d->base.sha1,
                                        base_obj->data, base_obj->size, type);
                find_unresolved_deltas(base_obj);
@@ -1090,7 +1249,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                fsync_or_die(output_fd, curr_pack_name);
                err = close(output_fd);
                if (err)
-                       die_errno("error while closing pack file");
+                       die_errno(_("error while closing pack file"));
        }
 
        if (keep_msg) {
@@ -1103,7 +1262,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
 
                if (keep_fd < 0) {
                        if (errno != EEXIST)
-                               die_errno("cannot write keep file '%s'",
+                               die_errno(_("cannot write keep file '%s'"),
                                          keep_name);
                } else {
                        if (keep_msg_len > 0) {
@@ -1111,7 +1270,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                                write_or_die(keep_fd, "\n", 1);
                        }
                        if (close(keep_fd) != 0)
-                               die_errno("cannot close written keep file '%s'",
+                               die_errno(_("cannot close written keep file '%s'"),
                                    keep_name);
                        report = "keep";
                }
@@ -1124,7 +1283,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                        final_pack_name = name;
                }
                if (move_temp_to_file(curr_pack_name, final_pack_name))
-                       die("cannot store pack file");
+                       die(_("cannot store pack file"));
        } else if (from_stdin)
                chmod(final_pack_name, 0444);
 
@@ -1135,7 +1294,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                        final_index_name = name;
                }
                if (move_temp_to_file(curr_index_name, final_index_name))
-                       die("cannot store index file");
+                       die(_("cannot store index file"));
        } else
                chmod(final_index_name, 0444);
 
@@ -1236,9 +1395,9 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
        struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1);
 
        if (!p)
-               die("Cannot open existing pack file '%s'", pack_name);
+               die(_("Cannot open existing pack file '%s'"), pack_name);
        if (open_pack_index(p))
-               die("Cannot open existing pack idx file for '%s'", pack_name);
+               die(_("Cannot open existing pack idx file for '%s'"), pack_name);
 
        /* Read the attributes from the existing idx file */
        opts->version = p->index_version;
@@ -1285,15 +1444,18 @@ static void show_pack_info(int stat_only)
        }
 
        if (baseobjects)
-               printf("non delta: %d object%s\n",
-                      baseobjects, baseobjects > 1 ? "s" : "");
+               printf_ln(Q_("non delta: %d object",
+                            "non delta: %d objects",
+                            baseobjects),
+                         baseobjects);
        for (i = 0; i < deepest_delta; i++) {
                if (!chain_histogram[i])
                        continue;
-               printf("chain length = %d: %lu object%s\n",
-                      i + 1,
-                      chain_histogram[i],
-                      chain_histogram[i] > 1 ? "s" : "");
+               printf_ln(Q_("chain length = %d: %lu object",
+                            "chain length = %d: %lu objects",
+                            chain_histogram[i]),
+                         i + 1,
+                         chain_histogram[i]);
        }
 }
 
@@ -1316,7 +1478,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        reset_pack_idx_option(&opts);
        git_config(git_index_pack_config, &opts);
        if (prefix && chdir(prefix))
-               die("Cannot come back to cwd");
+               die(_("Cannot come back to cwd"));
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
@@ -1360,10 +1522,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                hdr->hdr_signature = htonl(PACK_SIGNATURE);
                                hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
                                if (*c != ',')
-                                       die("bad %s", arg);
+                                       die(_("bad %s"), arg);
                                hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
                                if (*c)
-                                       die("bad %s", arg);
+                                       die(_("bad %s"), arg);
                                input_len = sizeof(*hdr);
                        } else if (!strcmp(arg, "-v")) {
                                verbose = 1;
@@ -1375,11 +1537,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                char *c;
                                opts.version = strtoul(arg + 16, &c, 10);
                                if (opts.version > 2)
-                                       die("bad %s", arg);
+                                       die(_("bad %s"), arg);
                                if (*c == ',')
                                        opts.off32_limit = strtoul(c+1, &c, 0);
                                if (*c || opts.off32_limit & 0x80000000)
-                                       die("bad %s", arg);
+                                       die(_("bad %s"), arg);
                        } else
                                usage(index_pack_usage);
                        continue;
@@ -1393,11 +1555,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (!pack_name && !from_stdin)
                usage(index_pack_usage);
        if (fix_thin_pack && !from_stdin)
-               die("--fix-thin cannot be used without --stdin");
+               die(_("--fix-thin cannot be used without --stdin"));
        if (!index_name && pack_name) {
                int len = strlen(pack_name);
                if (!has_extension(pack_name, ".pack"))
-                       die("packfile name '%s' does not end with '.pack'",
+                       die(_("packfile name '%s' does not end with '.pack'"),
                            pack_name);
                index_name_buf = xmalloc(len);
                memcpy(index_name_buf, pack_name, len - 5);
@@ -1407,7 +1569,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (keep_msg && !keep_name && pack_name) {
                int len = strlen(pack_name);
                if (!has_extension(pack_name, ".pack"))
-                       die("packfile name '%s' does not end with '.pack'",
+                       die(_("packfile name '%s' does not end with '.pack'"),
                            pack_name);
                keep_name_buf = xmalloc(len);
                memcpy(keep_name_buf, pack_name, len - 5);
@@ -1416,7 +1578,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        }
        if (verify) {
                if (!index_name)
-                       die("--verify with no packfile name given");
+                       die(_("--verify with no packfile name given"));
                read_idx_option(&opts, index_name);
                opts.flags |= WRITE_IDX_VERIFY | WRITE_IDX_STRICT;
        }