git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 14/14] index-pack: resolve v4 one-base trees

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Sep 8, 2013, 07:22 UTC
Message-ID
<1378624960-8919-15-git-send-email-pclouds@gmail.com>
In-Reply-To
<1378624960-8919-1-git-send-email-pclouds@gmail.com>

This is the most common case for delta trees. In fact it's the only kind that's produced by packv4-create. It fits well in the way index-pack resolves deltas and benefits from threading (the set of objects depending on this base does not overlap with the set of objects depending on another base)

Multi-base trees will be probably processed differently.
---
 builtin/index-pack.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 179 insertions(+), 16 deletions(-)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index ce06473..88340b5 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -12,6 +12,8 @@
 #include "streaming.h"
 #include "thread-utils.h"
 #include "packv4-parse.h"
+#include "varint.h"
+#include "tree-walk.h"
 
 static const char index_pack_usage[] =
 "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -38,8 +40,8 @@ struct base_data {
 	struct object_entry *obj;
 	void *data;
 	unsigned long size;
-	int ref_first, ref_last;
-	int ofs_first, ofs_last;
+	int ref_first, ref_last, tree_first;
+	int ofs_first, ofs_last, tree_last;
 };
 
 #if !defined(NO_PTHREADS) && defined(NO_THREAD_SAFE_PREAD)
@@ -430,6 +432,7 @@ static struct base_data *alloc_base_data(void)
 	memset(base, 0, sizeof(*base));
 	base->ref_last = -1;
 	base->ofs_last = -1;
+	base->tree_last = -1;
 	return base;
 }
 
@@ -670,6 +673,8 @@ static void *unpack_tree_v4(struct object_entry *obj,
 	}
 
 	if (last_base) {
+		if (nr_deltas - delta_start > 1)
+			die("sorry guys, multi-base trees are not supported yet");
 		strbuf_release(&sb);
 		return NULL;
 	} else {
@@ -800,6 +805,84 @@ static void *unpack_raw_entry(struct object_entry *obj,
 }
 
 /*
+ * Some checks are skipped because they are already done by
+ * unpack_tree_v4() in the first pass.
+ */
+static void *patch_one_base_tree(const struct object_entry *src,
+				 const unsigned char *src_buf,
+				 const unsigned char *delta_buf,
+				 unsigned long delta_size,
+				 unsigned long *dst_size)
+{
+	int nr;
+	const unsigned char *last_base = NULL;
+	struct strbuf sb = STRBUF_INIT;
+	const unsigned char *p = delta_buf;
+
+	nr = decode_varint(&p);
+	while (nr > 0 && p < delta_buf + delta_size) {
+		unsigned int copy_start_or_path = decode_varint(&p);
+		if (copy_start_or_path & 1) { /* copy_start */
+			struct tree_desc desc;
+			struct name_entry entry;
+			unsigned int copy_count = decode_varint(&p);
+			unsigned int copy_start = copy_start_or_path >> 1;
+			if (!src)
+				die("we are not supposed to copy from another tree!");
+			if (copy_count & 1) { /* first delta */
+				unsigned int id = decode_varint(&p);
+				if (!id) {
+					last_base = p;
+					p += 20;
+				} else
+					last_base = sha1_table + (id - 1) * 20;
+				if (hashcmp(last_base, src->idx.sha1))
+					die(_("bad tree base in patch_one_base_tree"));
+			}
+
+			copy_count >>= 1;
+			nr -= copy_count;
+
+			init_tree_desc(&desc, src_buf, src->size);
+			while (tree_entry(&desc, &entry)) {
+				if (copy_start)
+					copy_start--;
+				else if (copy_count) {
+					strbuf_addf(&sb, "%o %s%c",
+						    entry.mode, entry.path, '\0');
+					strbuf_add(&sb, entry.sha1, 20);
+					copy_count--;
+				} else
+					break;
+			}
+		} else {	/* path */
+			unsigned int path_idx = copy_start_or_path >> 1;
+			const unsigned char *path;
+			unsigned mode;
+			unsigned int id;
+			const unsigned char *entry_sha1;
+
+			id = decode_varint(&p);
+			if (!id) {
+				entry_sha1 = p;
+				p += 20;
+			} else
+				entry_sha1 = sha1_table + (id - 1) * 20;
+			nr--;
+
+			path = path_dict->data + path_dict->offsets[path_idx];
+			mode = (path[0] << 8) | path[1];
+			strbuf_addf(&sb, "%o %s%c", mode, path+2, '\0');
+			strbuf_add(&sb, entry_sha1, 20);
+		}
+	}
+	if (nr != 0 || p != delta_buf + delta_size)
+		die(_("bad delta tree"));
+	*dst_size = sb.len;
+	return sb.buf;
+}
+
+/*
  * Unpack entry data in the second pass when the pack is already
  * stored on disk. consume call back is used for large-blob case. Must
  * be thread safe.
@@ -865,8 +948,33 @@ static void *unpack_data(struct object_entry *obj,
 	return data;
 }
 
+static void *get_tree_v4_from_pack(struct object_entry *obj,
+				   unsigned long *len_p)
+{
+	off_t from = obj[0].idx.offset + obj[0].hdr_size;
+	unsigned long len = obj[1].idx.offset - from;
+	unsigned char *data;
+	ssize_t n;
+
+	data = xmalloc(len);
+	n = pread(pack_fd, data, len, from);
+	if (n < 0)
+		die_errno(_("cannot pread pack file"));
+	if (!n)
+		die(Q_("premature end of pack file, %lu byte missing",
+		       "premature end of pack file, %lu bytes missing",
+		       len),
+		    len);
+	if (len_p)
+		*len_p = len;
+	return data;
+}
+
 static void *get_data_from_pack(struct object_entry *obj)
 {
+	if (obj->type == OBJ_PV4_COMMIT || obj->type == OBJ_PV4_TREE)
+		die("BUG: unsupported code path");
+
 	return unpack_data(obj, NULL, NULL);
 }
 
@@ -1093,14 +1201,25 @@ static void *get_base_data(struct base_data *c)
 		struct object_entry *obj = c->obj;
 		struct base_data **delta = NULL;
 		int delta_nr = 0, delta_alloc = 0;
+		unsigned long size, len;
 
-		while (is_delta_type(c->obj->type) && !c->data) {
+		while ((is_delta_type(c->obj->type) ||
+			(c->base && c->obj->type == OBJ_PV4_TREE)) &&
+		       !c->data) {
 			ALLOC_GROW(delta, delta_nr + 1, delta_alloc);
 			delta[delta_nr++] = c;
 			c = c->base;
 		}
 		if (!delta_nr) {
-			c->data = get_data_from_pack(obj);
+			if (c->obj->type == OBJ_PV4_TREE) {
+				void *tree_v4 = get_tree_v4_from_pack(obj, &len);
+				c->data = patch_one_base_tree(NULL, NULL,
+							      tree_v4, len, &size);
+				if (size != obj->size)
+					die("size mismatch");
+				free(tree_v4);
+			} else
+				c->data = get_data_from_pack(obj);
 			c->size = obj->size;
 			get_thread_data()->base_cache_used += c->size;
 			prune_base_data(c);
@@ -1110,11 +1229,18 @@ static void *get_base_data(struct base_data *c)
 			c = delta[delta_nr - 1];
 			obj = c->obj;
 			base = get_base_data(c->base);
-			raw = get_data_from_pack(obj);
-			c->data = patch_delta(
-				base, c->base->size,
-				raw, obj->size,
-				&c->size);
+			if (c->obj->type == OBJ_PV4_TREE) {
+				raw = get_tree_v4_from_pack(obj, &len);
+				c->data = patch_one_base_tree(c->base->obj, base,
+							      raw, len, &size);
+				if (size != obj->size)
+					die("size mismatch");
+			} else {
+				raw = get_data_from_pack(obj);
+				c->data = patch_delta(base, c->base->size,
+						      raw, obj->size,
+						      &c->size);
+			}
 			free(raw);
 			if (!c->data)
 				bad_object(obj->idx.offset, _("failed to apply delta"));
@@ -1130,6 +1256,8 @@ static void resolve_delta(struct object_entry *delta_obj,
 			  struct base_data *base, struct base_data *result)
 {
 	void *base_data, *delta_data;
+	int tree_v4 = delta_obj->type == OBJ_PV4_TREE;
+	unsigned long tree_size;
 
 	delta_obj->real_type = base->obj->real_type;
 	if (show_stat) {
@@ -1140,10 +1268,18 @@ static void resolve_delta(struct object_entry *delta_obj,
 		deepest_delta_unlock();
 	}
 	delta_obj->base_object_no = base->obj - objects;
-	delta_data = get_data_from_pack(delta_obj);
+	if (tree_v4)
+		delta_data = get_tree_v4_from_pack(delta_obj, &tree_size);
+	else
+		delta_data = get_data_from_pack(delta_obj);
 	base_data = get_base_data(base);
 	result->obj = delta_obj;
-	result->data = patch_delta(base_data, base->size,
+	if (tree_v4)
+		result->data = patch_one_base_tree(base->obj, base_data,
+						   delta_data, tree_size,
+						   &result->size);
+	else
+		result->data = patch_delta(base_data, base->size,
 				   delta_data, delta_obj->size, &result->size);
 	free(delta_data);
 	if (!result->data)
@@ -1166,7 +1302,8 @@ static void resolve_delta(struct object_entry *delta_obj,
 static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 						  struct base_data *prev_base)
 {
-	if (base->ref_last == -1 && base->ofs_last == -1) {
+	if (base->ref_last == -1 && base->ofs_last == -1 &&
+	    base->tree_last == -1) {
 		union delta_base base_spec;
 
 		hashcpy(base_spec.sha1, base->obj->idx.sha1);
@@ -1179,9 +1316,15 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 			find_delta_children(&base_spec,
 					    &base->ofs_first, &base->ofs_last,
 					    OBJ_OFS_DELTA);
+		} else {
+			hashcpy(base_spec.sha1, base->obj->idx.sha1);
+			find_delta_children(&base_spec,
+					    &base->tree_first, &base->tree_last,
+					    OBJ_PV4_TREE);
 		}
 
-		if (base->ref_last == -1 && base->ofs_last == -1) {
+		if (base->ref_last == -1 && base->ofs_last == -1 &&
+		    base->tree_last == -1) {
 			free(base->data);
 			return NULL;
 		}
@@ -1215,6 +1358,25 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 		return result;
 	}
 
+	while (base->tree_first <= base->tree_last) {
+		struct object_entry *child = objects + deltas[base->tree_first].obj_no;
+		struct base_data *result;
+
+		assert(child->type == OBJ_PV4_TREE);
+		if (child->nr_bases > 1) {
+			/* maybe resolved in the third pass or something */
+			base->tree_first++;
+			continue;
+		}
+		result = alloc_base_data();
+		resolve_delta(child, base, result);
+		if (base->tree_first == base->tree_last)
+			free_base_data(base);
+
+		base->tree_first++;
+		return result;
+	}
+
 	unlink_base_data(base);
 	return NULL;
 }
@@ -1273,7 +1435,8 @@ static void *threaded_second_pass(void *data)
 		counter_unlock();
 		work_lock();
 		while (nr_dispatched < nr_objects &&
-		       is_delta_type(objects[nr_dispatched].type))
+		       (is_delta_type(objects[nr_dispatched].type) ||
+			is_delta_tree(objects + nr_dispatched)))
 			nr_dispatched++;
 		if (nr_dispatched >= nr_objects) {
 			work_unlock();
@@ -1427,7 +1590,7 @@ static void resolve_deltas(void)
 	for (i = 0; i < nr_objects; i++) {
 		struct object_entry *obj = &objects[i];
 
-		if (is_delta_type(obj->type))
+		if (is_delta_type(obj->type) || is_delta_tree(obj))
 			continue;
 		resolve_base(obj);
 		display_progress(progress, nr_resolved_deltas);
@@ -1972,7 +2135,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
 		show_pack_info(stat_only);
 
 	if (packv4)
-		die("we're not there yet");
+		opts.version = 3;
 
 	idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
 	for (i = 0; i < nr_objects; i++)
-- 
1.8.2.83.gc99314b
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 81 of 124 in “pack version 4 basic functionalities”
  1. 00/38 pack version 4 basic functionalitiesNicolas Pitre, Sep 5, 2013
  2. 01/38 pack v4: initial pack dictionary structure and codeNicolas Pitre, Sep 5, 2013
  3. 02/38 export packed_object_info()Nicolas Pitre, Sep 5, 2013
  4. 03/38 pack v4: scan tree objectsNicolas Pitre, Sep 5, 2013
  5. 04/38 pack v4: add tree entry mode support to dictionary entriesNicolas Pitre, Sep 5, 2013
  6. 05/38 pack v4: add commit object parsingNicolas Pitre, Sep 5, 2013
  7. SZEDER GáborSep 5, 2013
  8. Nicolas PitreSep 5, 2013
  9. 06/38 pack v4: split the object list and dictionary creationNicolas Pitre, Sep 5, 2013
  10. 07/38 pack v4: move to struct pack_idx_entry and get rid of our own struct idx_entryNicolas Pitre, Sep 5, 2013
  11. 08/38 pack v4: basic SHA1 reference encodingNicolas Pitre, Sep 5, 2013
  12. 09/38 introduce get_sha1_lowhex()Nicolas Pitre, Sep 5, 2013
  13. 10/38 pack v4: commit object encodingNicolas Pitre, Sep 5, 2013
  14. Junio C HamanoSep 6, 2013
  15. Nicolas PitreSep 6, 2013
  16. Junio C HamanoSep 6, 2013
  17. Nicolas PitreSep 7, 2013
  18. 11/38 pack v4: tree object encodingNicolas Pitre, Sep 5, 2013
  19. 12/38 pack v4: dictionary table outputNicolas Pitre, Sep 5, 2013
  20. 13/38 pack v4: creation codeNicolas Pitre, Sep 5, 2013
  21. 14/38 pack v4: object headersNicolas Pitre, Sep 5, 2013
  22. 15/38 pack v4: object data copyNicolas Pitre, Sep 5, 2013
  23. 16/38 pack v4: object writingNicolas Pitre, Sep 5, 2013
  24. 17/38 pack v4: tree object delta encodingNicolas Pitre, Sep 5, 2013
  25. 18/38 pack v4: load delta candidate for encoding tree objectsNicolas Pitre, Sep 5, 2013
  26. 19/38 packv4-create: optimize delta encodingNicolas Pitre, Sep 5, 2013
  27. 20/38 pack v4: honor pack.compression config optionNicolas Pitre, Sep 5, 2013
  28. 21/38 pack v4: relax commit parsing a bitNicolas Pitre, Sep 5, 2013
  29. 22/38 pack index v3Nicolas Pitre, Sep 5, 2013
  30. 23/38 packv4-create: normalize pack name to properly generate the pack index file nameNicolas Pitre, Sep 5, 2013
  31. 24/38 packv4-create: add progress displayNicolas Pitre, Sep 5, 2013
  32. 25/38 pack v4: initial pack index v3 support on the read sideNicolas Pitre, Sep 5, 2013
  33. 26/38 pack v4: object header decodeNicolas Pitre, Sep 5, 2013
  34. 27/38 pack v4: code to obtain a SHA1 from a sha1refNicolas Pitre, Sep 5, 2013
  35. 28/38 pack v4: code to load and prepare a pack dictionary table for useNicolas Pitre, Sep 5, 2013
  36. 29/38 pack v4: code to retrieve a nameNicolas Pitre, Sep 5, 2013
  37. 30/38 pack v4: code to recreate a canonical commit objectNicolas Pitre, Sep 5, 2013
  38. 31/38 sha1_file.c: make use of decode_varint()Nicolas Pitre, Sep 5, 2013
  39. SZEDER GáborSep 5, 2013
  40. 32/38 pack v4: parse delta base referenceNicolas Pitre, Sep 5, 2013
  41. 33/38 pack v4: we can read commit objects nowNicolas Pitre, Sep 5, 2013
  42. 34/38 pack v4: code to retrieve a path componentNicolas Pitre, Sep 5, 2013
  43. 35/38 pack v4: decode tree objectsNicolas Pitre, Sep 5, 2013
  44. 36/38 pack v4: get tree objectsNicolas Pitre, Sep 5, 2013
  45. 37/38 pack v4: introduce "escape hatches" in the name and path indexesNicolas Pitre, Sep 5, 2013
  46. Nicolas PitreSep 5, 2013
  47. Nicolas PitreSep 5, 2013
  48. Duy NguyenSep 5, 2013
  49. 38/38 packv4-create: add a command line argument to limit tree copy sequencesNicolas Pitre, Sep 5, 2013
  50. 00/12 pack v4 support in index-packNguyễn Thái Ngọc Duy, Sep 7, 2013
  51. 01/12 pack v4: split pv4_create_dict() out of load_dict()Nguyễn Thái Ngọc Duy, Sep 7, 2013
  52. 02/12 index-pack: split out varint decoding codeNguyễn Thái Ngọc Duy, Sep 7, 2013
  53. 03/12 index-pack: do not allocate buffer for unpacking deltas in the first passNguyễn Thái Ngọc Duy, Sep 7, 2013
  54. 04/12 index-pack: split inflate/digest code out of unpack_entry_dataNguyễn Thái Ngọc Duy, Sep 7, 2013
  55. 05/12 index-pack: parse v4 header and dictionariesNguyễn Thái Ngọc Duy, Sep 7, 2013
  56. Nicolas PitreSep 8, 2013
  57. 06/12 index-pack: make sure all objects are registered in v4's SHA-1 tableNguyễn Thái Ngọc Duy, Sep 7, 2013
  58. 07/12 index-pack: parse v4 commit formatNguyễn Thái Ngọc Duy, Sep 7, 2013
  59. 08/12 index-pack: parse v4 tree formatNguyễn Thái Ngọc Duy, Sep 7, 2013
  60. Nicolas PitreSep 8, 2013
  61. 09/12 index-pack: move delta base queuing code to unpack_raw_entryNguyễn Thái Ngọc Duy, Sep 7, 2013
  62. 10/12 index-pack: record all delta bases in v4 (tree and ref-delta)Nguyễn Thái Ngọc Duy, Sep 7, 2013
  63. 11/12 index-pack: skip looking for ofs-deltas in v4 as they are not allowedNguyễn Thái Ngọc Duy, Sep 7, 2013
  64. 12/12 index-pack: resolve v4 one-base treesNguyễn Thái Ngọc Duy, Sep 7, 2013
  65. Nicolas PitreSep 8, 2013
  66. Duy NguyenSep 8, 2013
  67. 00/14 pack v4 support in index-packNguyễn Thái Ngọc Duy, Sep 8, 2013
  68. 01/14 pack v4: split pv4_create_dict() out of load_dict()Nguyễn Thái Ngọc Duy, Sep 8, 2013
  69. 02/14 pack v4: add pv4_free_dict()Nguyễn Thái Ngọc Duy, Sep 8, 2013
  70. 03/14 index-pack: add more comments on some big functionsNguyễn Thái Ngọc Duy, Sep 8, 2013
  71. 04/14 index-pack: split out varint decoding codeNguyễn Thái Ngọc Duy, Sep 8, 2013
  72. 05/14 index-pack: do not allocate buffer for unpacking deltas in the first passNguyễn Thái Ngọc Duy, Sep 8, 2013
  73. 06/14 index-pack: split inflate/digest code out of unpack_entry_dataNguyễn Thái Ngọc Duy, Sep 8, 2013
  74. 07/14 index-pack: parse v4 header and dictionariesNguyễn Thái Ngọc Duy, Sep 8, 2013
  75. 08/14 index-pack: make sure all objects are registered in v4's SHA-1 tableNguyễn Thái Ngọc Duy, Sep 8, 2013
  76. 09/14 index-pack: parse v4 commit formatNguyễn Thái Ngọc Duy, Sep 8, 2013
  77. 10/14 index-pack: parse v4 tree formatNguyễn Thái Ngọc Duy, Sep 8, 2013
  78. 11/14 index-pack: move delta base queuing code to unpack_raw_entryNguyễn Thái Ngọc Duy, Sep 8, 2013
  79. 12/14 index-pack: record all delta bases in v4 (tree and ref-delta)Nguyễn Thái Ngọc Duy, Sep 8, 2013
  80. 13/14 index-pack: skip looking for ofs-deltas in v4 as they are not allowedNguyễn Thái Ngọc Duy, Sep 8, 2013
  81. 14/14 index-pack: resolve v4 one-base treesNguyễn Thái Ngọc Duy, Sep 8, 2013
  82. 00/11 pack v4 support in pack-objectsNguyễn Thái Ngọc Duy, Sep 8, 2013
  83. 01/11 pack v4: allocate dicts from the beginningNguyễn Thái Ngọc Duy, Sep 8, 2013
  84. 02/11 pack v4: stop using static/global variables in packv4-create.cNguyễn Thái Ngọc Duy, Sep 8, 2013
  85. 03/11 pack v4: move packv4-create.c to libgit.aNguyễn Thái Ngọc Duy, Sep 8, 2013
  86. Nicolas PitreSep 8, 2013
  87. 04/11 pack v4: add version argument to write_pack_headerNguyễn Thái Ngọc Duy, Sep 8, 2013
  88. 05/11 pack-write.c: add pv4_encode_in_pack_object_headerNguyễn Thái Ngọc Duy, Sep 8, 2013
  89. Nicolas PitreSep 8, 2013
  90. 06/11 pack-objects: add --version to specify written pack versionNguyễn Thái Ngọc Duy, Sep 8, 2013
  91. 07/11 list-objects.c: add show_tree_entry callback to traverse_commit_listNguyễn Thái Ngọc Duy, Sep 8, 2013
  92. 08/11 pack-objects: create pack v4 tablesNguyễn Thái Ngọc Duy, Sep 8, 2013
  93. Duy NguyenSep 9, 2013
  94. Nicolas PitreSep 9, 2013
  95. Junio C HamanoSep 9, 2013
  96. 09/11 pack-objects: do not cache delta for v4 treesNguyễn Thái Ngọc Duy, Sep 8, 2013
  97. 10/11 pack-objects: exclude commits out of delta objects in v4Nguyễn Thái Ngọc Duy, Sep 8, 2013
  98. 11/11 pack-objects: support writing pack v4Nguyễn Thái Ngọc Duy, Sep 8, 2013
  99. 00/16 pack v4 support in pack-objectsNguyễn Thái Ngọc Duy, Sep 9, 2013
  100. 01/16 pack v4: allocate dicts from the beginningNguyễn Thái Ngọc Duy, Sep 9, 2013
  101. 02/16 pack v4: stop using static/global variables in packv4-create.cNguyễn Thái Ngọc Duy, Sep 9, 2013
  102. 03/16 pack v4: move packv4-create.c to libgit.aNguyễn Thái Ngọc Duy, Sep 9, 2013
  103. 04/16 pack v4: add version argument to write_pack_headerNguyễn Thái Ngọc Duy, Sep 9, 2013
  104. 05/16 pack_write: tighten valid object type check in encode_in_pack_object_headerNguyễn Thái Ngọc Duy, Sep 9, 2013
  105. 06/16 pack-write.c: add pv4_encode_object_headerNguyễn Thái Ngọc Duy, Sep 9, 2013
  106. 07/16 pack-objects: add --version to specify written pack versionNguyễn Thái Ngọc Duy, Sep 9, 2013
  107. 08/16 list-objects.c: add show_tree_entry callback to traverse_commit_listNguyễn Thái Ngọc Duy, Sep 9, 2013
  108. 09/16 pack-objects: do not cache delta for v4 treesNguyễn Thái Ngọc Duy, Sep 9, 2013
  109. 10/16 pack-objects: exclude commits out of delta objects in v4Nguyễn Thái Ngọc Duy, Sep 9, 2013
  110. 11/16 pack-objects: create pack v4 tablesNguyễn Thái Ngọc Duy, Sep 9, 2013
  111. 12/16 pack-objects: prepare SHA-1 table in v4Nguyễn Thái Ngọc Duy, Sep 9, 2013
  112. 13/16 pack-objects: support writing pack v4Nguyễn Thái Ngọc Duy, Sep 9, 2013
  113. 14/16 pack v4: support "end-of-pack" indicator in index-pack and pack-objectsNguyễn Thái Ngọc Duy, Sep 9, 2013
  114. 15/16 index-pack: use nr_objects_final as sha1_table sizeNguyễn Thái Ngọc Duy, Sep 9, 2013
  115. Nicolas PitreSep 9, 2013
  116. Junio C HamanoSep 9, 2013
  117. Nicolas PitreSep 9, 2013
  118. Junio C HamanoSep 9, 2013
  119. Nicolas PitreSep 9, 2013
  120. Junio C HamanoSep 9, 2013
  121. Nicolas PitreSep 9, 2013
  122. Duy NguyenSep 10, 2013
  123. Nicolas PitreSep 12, 2013
  124. 16/16 index-pack: support completing thin packs v4Nguyễn Thái Ngọc Duy, Sep 9, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.