On Fri, 6 Sep 2013, Nguyễn Thái Ngọc Duy wrote: > > Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> > --- > Should be up to date with Nico's latest implementation and also cover > additions to the format that everybody seems to agree on: > > - new types for canonical trees and commits > - sha-1 table covering missing objects in thin packs Yes, I've tweaked the format again. I've implemented the code needed to carry canonical commit and tree objects in pack v4. And things are much simpler if the canonical commit and tree types are identical to pack v2. Therefore the new types are used for the pack v4 optimized commit and tree representations. I've therefore added this patch to my tree (with the needed changes to the documentation patch): commit 98d4b75aff266015b5dff0a324a2984c2a8f7fa2 Author: Nicolas Pitre <nico@xxxxxxxxxxx> Date: Fri Sep 6 23:45:49 2013 -0400 pack v4: allow canonical commit and tree objects If for some reason we can't transcode a commit or tree object (lossy encoding such as the zero-padded file mode for example) then we can still store the canonical object like in pack v2. This is also useful for completing a thin pack without having to add missing entries to the dictionary tables. To simplify things, the canonical commit and tree types retain their type number 1 and 2 respectively, and the transcoded types are now 9 and 10 i.e. with bit 3 added. Signed-off-by: Nicolas Pitre <nico@xxxxxxxxxxx> diff --git a/cache.h b/cache.h index a6d016b..b68ad5a 100644 --- a/cache.h +++ b/cache.h @@ -330,6 +330,8 @@ enum object_type { /* 5 for future expansion */ OBJ_OFS_DELTA = 6, OBJ_REF_DELTA = 7, + OBJ_PV4_COMMIT = (8 + 1), + OBJ_PV4_TREE = (8 + 2), OBJ_ANY, OBJ_MAX }; diff --git a/packv4-create.c b/packv4-create.c index 11cfe6f..38fa594 100644 --- a/packv4-create.c +++ b/packv4-create.c @@ -981,10 +981,15 @@ static off_t packv4_write_object(struct sha1file *f, struct packed_git *p, die("unexpected object type %d", type); } free(src); - if (!result) - die("can't convert %s object %s", - typename(type), sha1_to_hex(obj->sha1)); + if (!result) { + warning("can't convert %s object %s", + typename(type), sha1_to_hex(obj->sha1)); + /* fall back to copy the object in its original form */ + return copy_object_data(f, p, obj->offset); + } + /* Use bit 3 to indicate a special type encoding */ + type += 8; hdrlen = write_object_header(f, type, obj_size); sha1write(f, result, buf_size); free(result); diff --git a/packv4-parse.c b/packv4-parse.c index 86ec535..63bba03 100644 --- a/packv4-parse.c +++ b/packv4-parse.c @@ -266,7 +266,7 @@ static int decode_entries(struct packed_git *p, struct pack_window **w_curs, if (++scp - src >= avail - 20) return -1; /* let's still make sure this is actually a tree */ - if ((*scp++ & 0xf) != OBJ_TREE) + if ((*scp++ & 0xf) != OBJ_PV4_TREE) return -1; } diff --git a/sha1_file.c b/sha1_file.c index 79e1293..c7bf677 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1806,6 +1806,11 @@ static enum object_type packed_to_object_type(struct packed_git *p, } switch (type) { + case OBJ_PV4_COMMIT: + case OBJ_PV4_TREE: + /* hide pack v4 special object types */ + type -= 8; + break; case OBJ_BAD: case OBJ_COMMIT: case OBJ_TREE: @@ -2171,17 +2176,16 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset, if (data) die("BUG in unpack_entry: left loop at a valid delta"); break; + case OBJ_PV4_COMMIT: + data = pv4_get_commit(p, &w_curs, curpos, size); + type -= 8; + break; + case OBJ_PV4_TREE: + data = pv4_get_tree(p, &w_curs, curpos, size); + type -= 8; + break; case OBJ_COMMIT: case OBJ_TREE: - if (p->version >= 4 && !base_from_cache) { - if (type == OBJ_COMMIT) { - data = pv4_get_commit(p, &w_curs, curpos, size); - } else { - data = pv4_get_tree(p, &w_curs, curpos, size); - } - break; - } - /* fall through */ case OBJ_BLOB: case OBJ_TAG: if (!base_from_cache)