#endif
static const char pack_usage[] = "\
-git-pack-objects [{ -q | --progress | --all-progress }] \n\
+git pack-objects [{ -q | --progress | --all-progress }] \n\
[--max-pack-size=N] [--local] [--incremental] \n\
[--window=N] [--window-memory=N] [--depth=N] \n\
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
- [--stdout | base-name] [--include-tag] [--keep-unreachable] \n\
+ [--stdout | base-name] [--include-tag] \n\
+ [--keep-unreachable | --unpack-unreachable] \n\
[<ref-list | <object-list]";
struct object_entry {
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
-static int keep_unreachable, include_tag;
+static int keep_unreachable, unpack_unreachable, include_tag;
static int local;
static int incremental;
static int allow_ofs_delta;
stream.total_in == len) ? 0 : -1;
}
-static int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,
- off_t offset, off_t len, unsigned int nr)
-{
- const uint32_t *index_crc;
- uint32_t data_crc = crc32(0, Z_NULL, 0);
-
- do {
- unsigned int avail;
- void *data = use_pack(p, w_curs, offset, &avail);
- if (avail > len)
- avail = len;
- data_crc = crc32(data_crc, data, avail);
- offset += avail;
- len -= avail;
- } while (len);
-
- index_crc = p->index_data;
- index_crc += 2 + 256 + p->num_objects * (20/4) + nr;
-
- return data_crc != ntohl(*index_crc);
-}
-
static void copy_pack_data(struct sha1file *f,
struct packed_git *p,
struct pack_window **w_curs,
return hdrlen + datalen;
}
-static off_t write_one(struct sha1file *f,
+static int write_one(struct sha1file *f,
struct object_entry *e,
- off_t offset)
+ off_t *offset)
{
unsigned long size;
/* offset is non zero if object is written already. */
if (e->idx.offset || e->preferred_base)
- return offset;
+ return 1;
/* if we are deltified, write out base object first. */
- if (e->delta) {
- offset = write_one(f, e->delta, offset);
- if (!offset)
- return 0;
- }
+ if (e->delta && !write_one(f, e->delta, offset))
+ return 0;
- e->idx.offset = offset;
- size = write_object(f, e, offset);
+ e->idx.offset = *offset;
+ size = write_object(f, e, *offset);
if (!size) {
e->idx.offset = 0;
return 0;
written_list[nr_written++] = &e->idx;
/* make sure off_t is sufficiently large not to wrap */
- if (offset > offset + size)
+ if (*offset > *offset + size)
die("pack too large for current definition of off_t");
- return offset + size;
+ *offset += size;
+ return 1;
}
/* forward declaration for write_pack_file */
{
uint32_t i = 0, j;
struct sha1file *f;
- off_t offset, offset_one, last_obj_offset = 0;
+ off_t offset;
struct pack_header hdr;
uint32_t nr_remaining = nr_result;
time_t last_mtime = 0;
offset = sizeof(hdr);
nr_written = 0;
for (; i < nr_objects; i++) {
- last_obj_offset = offset;
- offset_one = write_one(f, objects + i, offset);
- if (!offset_one)
+ if (!write_one(f, objects + i, &offset))
break;
- offset = offset_one;
display_progress(progress_state, written);
}
* Did we write the wrong # entries in the header?
* If so, rewrite it like in fast-import
*/
- if (pack_to_stdout || nr_written == nr_remaining) {
- sha1close(f, sha1, 1);
+ if (pack_to_stdout) {
+ sha1close(f, sha1, CSUM_CLOSE);
+ } else if (nr_written == nr_remaining) {
+ sha1close(f, sha1, CSUM_FSYNC);
} else {
- int fd = sha1close(f, NULL, 0);
- fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
+ int fd = sha1close(f, sha1, 0);
+ fixup_pack_header_footer(fd, sha1, pack_tmp_name,
+ nr_written, sha1, offset);
close(fd);
}
free(written_list);
stop_progress(&progress_state);
if (written != nr_result)
- die("wrote %u objects while expecting %u", written, nr_result);
+ die("wrote %"PRIu32" objects while expecting %"PRIu32,
+ written, nr_result);
/*
* We have scanned through [0 ... i). Since we have written
* the correct number of objects, the remaining [i ... nr_objects)
j += !e->idx.offset && !e->preferred_base;
}
if (j)
- die("wrote %u objects as expected but %u unwritten", written, j);
+ die("wrote %"PRIu32" objects as expected but %"PRIu32
+ " unwritten", written, j);
}
static int locate_object_entry_hash(const unsigned char *sha1)
}
entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
- if (entry->type < 0)
- die("unable to get type of object %s",
- sha1_to_hex(entry->idx.sha1));
+ /*
+ * The error condition is checked in prepare_pack(). This is
+ * to permit a missing preferred base object to be ignored
+ * as a preferred base. Doing so can result in a larger
+ * pack file, but the transfer will still take place.
+ */
}
static int pack_offset_sort(const void *_a, const void *_b)
sorted_by_offset[i] = objects + i;
qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
- init_pack_revindex();
-
for (i = 0; i < nr_objects; i++)
check_object(sorted_by_offset[i]);
static void prepare_pack(int window, int depth)
{
struct object_entry **delta_list;
- uint32_t i, n, nr_deltas;
+ uint32_t i, nr_deltas;
+ unsigned n;
get_object_details();
if (entry->no_try_delta)
continue;
- if (!entry->preferred_base)
+ if (!entry->preferred_base) {
nr_deltas++;
+ if (entry->type < 0)
+ die("unable to get type of object %s",
+ sha1_to_hex(entry->idx.sha1));
+ }
delta_list[n++] = entry;
}
free(delta_list);
}
-static int git_pack_config(const char *k, const char *v)
+static int git_pack_config(const char *k, const char *v, void *cb)
{
if(!strcmp(k, "pack.window")) {
window = git_config_int(k, v);
if (!strcmp(k, "pack.indexversion")) {
pack_idx_default_version = git_config_int(k, v);
if (pack_idx_default_version > 2)
- die("bad pack.indexversion=%d", pack_idx_default_version);
+ die("bad pack.indexversion=%"PRIu32,
+ pack_idx_default_version);
return 0;
}
if (!strcmp(k, "pack.packsizelimit")) {
pack_size_limit_cfg = git_config_ulong(k, v);
return 0;
}
- return git_default_config(k, v);
+ return git_default_config(k, v, cb);
}
static void read_object_list_from_stdin(void)
/*
* Compare the objects in the offset order, in order to emulate the
- * "git-rev-list --objects" output that produced the pack originally.
+ * "git rev-list --objects" output that produced the pack originally.
*/
static int ofscmp(const void *a_, const void *b_)
{
free(in_pack.array);
}
+static void loosen_unused_packed_objects(struct rev_info *revs)
+{
+ struct packed_git *p;
+ uint32_t i;
+ const unsigned char *sha1;
+
+ for (p = packed_git; p; p = p->next) {
+ for (i = 0; i < revs->num_ignore_packed; i++) {
+ if (matches_pack_name(p, revs->ignore_packed[i]))
+ break;
+ }
+ if (revs->num_ignore_packed <= i)
+ continue;
+
+ if (open_pack_index(p))
+ die("cannot open pack index");
+
+ for (i = 0; i < p->num_objects; i++) {
+ sha1 = nth_packed_object_sha1(p, i);
+ if (!locate_object_entry(sha1))
+ if (force_object_loose(sha1, p->mtime))
+ die("unable to force loose object");
+ }
+ }
+}
+
static void get_object_list(int ac, const char **av)
{
struct rev_info revs;
if (keep_unreachable)
add_objects_in_unpacked_packs(&revs);
+ if (unpack_unreachable)
+ loosen_unused_packed_objects(&revs);
}
static int adjust_perm(const char *path, mode_t mode)
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
rp_ac = 2;
- git_config(git_pack_config);
+ git_config(git_pack_config, NULL);
if (!pack_compression_seen && core_compression_seen)
pack_compression_level = core_compression_level;
keep_unreachable = 1;
continue;
}
+ if (!strcmp("--unpack-unreachable", arg)) {
+ unpack_unreachable = 1;
+ continue;
+ }
if (!strcmp("--include-tag", arg)) {
include_tag = 1;
continue;
if (!pack_to_stdout && thin)
die("--thin cannot be used to build an indexable pack.");
+ if (keep_unreachable && unpack_unreachable)
+ die("--keep-unreachable and --unpack-unreachable are incompatible.");
+
#ifdef THREADED_DELTA_SEARCH
if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus();
prepare_pack(window, depth);
write_pack_file();
if (progress)
- fprintf(stderr, "Total %u (delta %u), reused %u (delta %u)\n",
+ fprintf(stderr, "Total %"PRIu32" (delta %"PRIu32"),"
+ " reused %"PRIu32" (delta %"PRIu32")\n",
written, written_delta, reused, reused_delta);
return 0;
}