Commit Diff


commit - b36429aba0124d4bc92ec4dd7b285ace7abfcaee
commit + 7762fe12f8608c112ccb3bbada7235a2c4208fd0
blob - d0e80bc31edd85aea3d8e095d680ea7b47a23d0c
blob + be5add975f075e866935ce17ed6496c3e1439b20
--- lib/commit_graph.c
+++ lib/commit_graph.c
@@ -163,12 +163,12 @@ is_merge_point(struct got_commit_graph_node *node)
 }
 
 static const struct got_error *
-detect_changed_path(int *changed, struct got_commit_object *commit,
+detect_changed_path(int *changed, struct got_commit_object_mini *commit,
     struct got_object_id *commit_id, const char *path,
     struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
-	struct got_commit_object *pcommit = NULL;
+	struct got_commit_object_mini *pcommit = NULL;
 	struct got_tree_object *tree = NULL, *ptree = NULL;
 	struct got_object_qid *pid;
 
@@ -194,7 +194,7 @@ detect_changed_path(int *changed, struct got_commit_ob
 			*changed = 1; /* The path was created in this commit. */
 		free(obj_id);
 	} else {
-		err = got_object_open_as_commit(&pcommit, repo, pid->id);
+		err = got_object_open_mini_commit(&pcommit, repo, pid->id);
 		if (err)
 			goto done;
 
@@ -211,7 +211,7 @@ done:
 	if (ptree)
 		got_object_tree_close(ptree);
 	if (pcommit)
-		got_object_commit_close(pcommit);
+		got_object_mini_commit_close(pcommit);
 	return err;
 }
 
@@ -275,7 +275,7 @@ close_branch(struct got_commit_graph *graph, struct go
 static const struct got_error *
 advance_branch(struct got_commit_graph *graph,
     struct got_commit_graph_node *node,
-    struct got_object_id *commit_id, struct got_commit_object *commit,
+    struct got_object_id *commit_id, struct got_commit_object_mini *commit,
     struct got_repository *repo)
 {
 	const struct got_error *err;
@@ -382,8 +382,8 @@ free_node(struct got_commit_graph_node *node)
 static const struct got_error *
 add_node(struct got_commit_graph_node **new_node,
     struct got_commit_graph *graph, struct got_object_id *commit_id,
-    struct got_commit_object *commit, struct got_commit_graph_node *child_node,
-    struct got_repository *repo)
+    struct got_commit_object_mini *commit,
+    struct got_commit_graph_node *child_node, struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
 	struct got_commit_graph_node *node;
@@ -456,11 +456,11 @@ got_commit_graph_open(struct got_commit_graph **graph,
     int first_parent_traversal, struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
-	struct got_commit_object *commit;
+	struct got_commit_object_mini *commit;
 
 	*graph = NULL;
 
-	err = got_object_open_as_commit(&commit, repo, commit_id);
+	err = got_object_open_mini_commit(&commit, repo, commit_id);
 	if (err)
 		return err;
 
@@ -475,7 +475,7 @@ got_commit_graph_open(struct got_commit_graph **graph,
 
 	*graph = alloc_graph(path);
 	if (*graph == NULL) {
-		got_object_commit_close(commit);
+		got_object_mini_commit_close(commit);
 		return got_error_from_errno();
 	}
 
@@ -484,7 +484,7 @@ got_commit_graph_open(struct got_commit_graph **graph,
 
 	err = add_node(&(*graph)->head_node, *graph, commit_id, commit, NULL,
 	    repo);
-	got_object_commit_close(commit);
+	got_object_mini_commit_close(commit);
 	if (err) {
 		got_commit_graph_close(*graph);
 		*graph = NULL;
@@ -547,20 +547,20 @@ fetch_commits_from_open_branches(int *ncommits,
 	for (i = 0; i < arg.ntips; i++) {
 		struct got_object_id *commit_id;
 		struct got_commit_graph_node *child_node, *new_node;
-		struct got_commit_object *commit;
+		struct got_commit_object_mini *commit;
 		int changed;
 
 		commit_id = &graph->tips[i].id;
 		child_node = graph->tips[i].node;
 
-		err = got_object_open_as_commit(&commit, repo, commit_id);
+		err = got_object_open_mini_commit(&commit, repo, commit_id);
 		if (err)
 			break;
 
 		err = detect_changed_path(&changed, commit, commit_id,
 		    graph->path, repo);
 		if (err) {
-			got_object_commit_close(commit);
+			got_object_mini_commit_close(commit);
 			if (err->code != GOT_ERR_NO_OBJ)
 				break;
 			err = close_branch(graph, commit_id);
@@ -572,7 +572,7 @@ fetch_commits_from_open_branches(int *ncommits,
 			*changed_id = commit_id;
 		err = add_node(&new_node, graph, commit_id, commit, child_node,
 		    repo);
-		got_object_commit_close(commit);
+		got_object_mini_commit_close(commit);
 		if (err)
 			break;
 		if (new_node)
@@ -628,21 +628,21 @@ got_commit_graph_iter_start(struct got_commit_graph *g
 {
 	const struct got_error *err = NULL;
 	struct got_commit_graph_node *start_node;
-	struct got_commit_object *commit;
+	struct got_commit_object_mini *commit;
 	int changed;
 
 	start_node = got_object_idset_get(graph->node_ids, id);
 	if (start_node == NULL)
 		return got_error(GOT_ERR_NO_OBJ);
 
-	err = got_object_open_as_commit(&commit, repo, &start_node->id);
+	err = got_object_open_mini_commit(&commit, repo, &start_node->id);
 	if (err)
 		return err;
 
 	err = detect_changed_path(&changed, commit, &start_node->id,
 	    graph->path, repo);
 	if (err) {
-		got_object_commit_close(commit);
+		got_object_mini_commit_close(commit);
 		return err;
 	}
 
@@ -654,13 +654,13 @@ got_commit_graph_iter_start(struct got_commit_graph *g
 			err = fetch_commits_from_open_branches(&ncommits,
 			    &changed_id, graph, repo);
 			if (err) {
-				got_object_commit_close(commit);
+				got_object_mini_commit_close(commit);
 				return err;
 			}
 		}
 		start_node = got_object_idset_get(graph->node_ids, changed_id);
 	}
-	got_object_commit_close(commit);
+	got_object_mini_commit_close(commit);
 
 	graph->iter_node = start_node;
 	return NULL;
blob - fc8b2eef010a4a07760e360d7e9102d16791ddbd
blob + 95f019e89afcbce1f16aa9d9641ca1a175c5eec1
--- lib/got_lib_object.h
+++ lib/got_lib_object.h
@@ -48,3 +48,16 @@ struct got_blob_object {
 	uint8_t *read_buf;
 	struct got_object_id id;
 };
+
+/* Small version of got_commit_object. Used by commit graph. */
+struct got_commit_object_mini {
+	struct got_object_id *tree_id;
+	unsigned int nparents;
+	struct got_object_id_queue parent_ids;
+	struct tm tm_committer;	/* UTC */
+};
+
+const struct got_error *
+got_object_open_mini_commit(struct got_commit_object_mini **,
+    struct got_repository *, struct got_object_id *);
+void got_object_mini_commit_close(struct got_commit_object_mini *);
blob - b427544ee597fb40d4802b61166507af2c7f124e
blob + 99f5e6bdf1e4f1b801b6f3c9b5241f99b89c4231
--- lib/got_lib_object_parse.h
+++ lib/got_lib_object_parse.h
@@ -14,7 +14,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+const struct got_error *got_object_qid_alloc_partial(struct got_object_qid **);
 struct got_commit_object *got_object_commit_alloc_partial(void);
+struct got_commit_object_mini *got_object_mini_commit_alloc_partial(void);
+const struct got_error *got_object_commit_add_parent(struct got_commit_object *,
+    const char *);
 struct got_tree_entry *got_alloc_tree_entry_partial(void);
 const struct got_error *got_object_read_header_privsep(struct got_object**,
     struct got_repository *repo, int);
@@ -23,11 +27,16 @@ const struct got_error *got_object_read_blob_privsep(s
 const struct got_error *got_object_read_commit_privsep(
     struct got_commit_object **, struct got_object *, int,
     struct got_repository *);
+const struct got_error *got_object_read_mini_commit_privsep(
+    struct got_commit_object_mini **, struct got_object *, int,
+    struct got_repository *);
 const struct got_error *got_object_read_tree_privsep(struct got_tree_object **,
     struct got_object *, int, struct got_repository *);
 
 const struct got_error *got_object_parse_commit(struct got_commit_object **,
     char *, size_t);
+const struct got_error *got_object_parse_mini_commit(
+    struct got_commit_object_mini **, char *, size_t);
 const struct got_error *got_object_parse_tree(struct got_tree_object **,
     uint8_t *, size_t);
 const struct got_error *got_read_file_to_mem(uint8_t **, size_t *, FILE *);
@@ -42,5 +51,7 @@ const struct got_error *got_object_packed_read_privsep
     struct got_object_id *);
 const struct got_error *got_object_read_packed_commit_privsep(
     struct got_commit_object **, struct got_object *, struct got_pack *);
+const struct got_error *got_object_read_packed_mini_commit_privsep(
+    struct got_commit_object_mini **, struct got_object *, struct got_pack *);
 const struct got_error *got_object_read_packed_tree_privsep(
     struct got_tree_object **, struct got_object *, struct got_pack *);
blob - b39f11fe79428dd8bc9691d9b8b2300171346459
blob + e343c376c6a64789812c5c88e965304898f5d7d4
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
@@ -82,6 +82,8 @@ enum got_imsg_type {
 	GOT_IMSG_COMMIT_REQUEST,
 	GOT_IMSG_COMMIT,
 	GOT_IMSG_COMMIT_LOGMSG,
+	GOT_IMSG_MINI_COMMIT_REQUEST,
+	GOT_IMSG_MINI_COMMIT,
 	GOT_IMSG_TREE_REQUEST,
 	GOT_IMSG_TREE,
 	GOT_IMSG_TREE_ENTRY,
@@ -142,7 +144,15 @@ struct got_imsg_commit_object {
 	 */
 } __attribute__((__packed__));
 
+/* Structure for GOT_IMSG_MINI_COMMIT data. */
+struct got_imsg_commit_object_mini {
+	uint8_t tree_id[SHA1_DIGEST_LENGTH];
+	struct tm tm_committer;
+	int nparents;
 
+	/* Followed by 'nparents' SHA1_DIGEST_LENGTH length strings */
+} __attribute__((__packed__));
+
 /* Structure for GOT_IMSG_TREE_ENTRY. */
 struct got_imsg_tree_entry {
 	char id[SHA1_DIGEST_LENGTH];
@@ -202,8 +212,12 @@ const struct got_error *got_privsep_recv_obj(struct go
     struct imsgbuf *);
 const struct got_error *got_privsep_send_commit(struct imsgbuf *,
     struct got_commit_object *);
+const struct got_error *got_privsep_send_mini_commit(struct imsgbuf *,
+    struct got_commit_object_mini *);
 const struct got_error *got_privsep_recv_commit(struct got_commit_object **,
     struct imsgbuf *);
+const struct got_error *got_privsep_recv_mini_commit(
+    struct got_commit_object_mini **, struct imsgbuf *);
 const struct got_error *got_privsep_recv_tree(struct got_tree_object **,
     struct imsgbuf *);
 const struct got_error *got_privsep_send_tree(struct imsgbuf *,
@@ -214,4 +228,5 @@ const struct got_error *got_privsep_init_pack_child(st
     struct got_pack *, struct got_packidx *);
 const struct got_error *got_privsep_send_packed_obj_req(struct imsgbuf *, int,
     struct got_object_id *);
-const struct got_error *got_privsep_send_pack_child_ready(struct imsgbuf *);
+const struct got_error *got_privsep_send_mini_commit_req(struct imsgbuf *, int,
+    struct got_object *);
blob - c58c241572783b631a3bb336ed0daab98750a241
blob + de22dce4277a47abcc56218844d0eb77281f29be
--- lib/object.c
+++ lib/object.c
@@ -311,6 +311,41 @@ open_commit(struct got_commit_object **commit,
 	if (err == NULL) {
 		(*commit)->refcnt++;
 		err = got_repo_cache_commit(repo, &obj->id, *commit);
+	}
+
+	return err;
+}
+
+static const struct got_error *
+open_mini_commit(struct got_commit_object_mini **commit,
+    struct got_repository *repo, struct got_object *obj)
+{
+	const struct got_error *err = NULL;
+
+	*commit = NULL;
+
+	if (obj->type != GOT_OBJ_TYPE_COMMIT)
+		return got_error(GOT_ERR_OBJ_TYPE);
+
+	if (obj->flags & GOT_OBJ_FLAG_PACKED) {
+		struct got_pack *pack;
+		pack = got_repo_get_cached_pack(repo, obj->path_packfile);
+		if (pack == NULL) {
+			err = got_repo_cache_pack(&pack, repo,
+			    obj->path_packfile, NULL);
+			if (err)
+				return err;
+		}
+		err = got_object_read_packed_mini_commit_privsep(commit, obj,
+		    pack);
+	} else {
+		int fd;
+		err = open_loose_object(&fd, obj, repo);
+		if (err)
+			return err;
+		err = got_object_read_mini_commit_privsep(commit, obj, fd,
+		    repo);
+		close(fd);
 	}
 
 	return err;
@@ -348,6 +383,27 @@ got_object_commit_open(struct got_commit_object **comm
     struct got_repository *repo, struct got_object *obj)
 {
 	return open_commit(commit, repo, obj, 1);
+}
+
+const struct got_error *
+got_object_open_mini_commit(struct got_commit_object_mini **commit,
+    struct got_repository *repo, struct got_object_id *id)
+{
+	const struct got_error *err;
+	struct got_object *obj;
+
+	err = got_object_open(&obj, repo, id);
+	if (err)
+		return err;
+	if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
+		err = got_error(GOT_ERR_OBJ_TYPE);
+		goto done;
+	}
+
+	err = open_mini_commit(commit, repo, obj);
+done:
+	got_object_close(obj);
+	return err;
 }
 
 const struct got_error *
@@ -1074,7 +1130,6 @@ done:
 	return err;
 }
 
-
 static const struct got_error *
 request_commit(struct got_commit_object **commit, struct got_repository *repo,
     struct got_object *obj, int fd)
@@ -1089,6 +1144,22 @@ request_commit(struct got_commit_object **commit, stru
 		return err;
 
 	return got_privsep_recv_commit(commit, ibuf);
+}
+
+static const struct got_error *
+request_mini_commit(struct got_commit_object_mini **commit,
+    struct got_repository *repo, struct got_object *obj, int fd)
+{
+	const struct got_error *err = NULL;
+	struct imsgbuf *ibuf;
+
+	ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf;
+
+	err = got_privsep_send_mini_commit_req(ibuf, fd, obj);
+	if (err)
+		return err;
+
+	return got_privsep_recv_mini_commit(commit, ibuf);
 }
 
 const struct got_error *
@@ -1105,6 +1176,20 @@ got_object_read_packed_commit_privsep(struct got_commi
 }
 
 const struct got_error *
+got_object_read_packed_mini_commit_privsep(struct got_commit_object_mini **commit,
+    struct got_object *obj, struct got_pack *pack)
+{
+	const struct got_error *err = NULL;
+
+	err = got_privsep_send_mini_commit_req(pack->privsep_child->ibuf, -1,
+	    obj);
+	if (err)
+		return err;
+
+	return got_privsep_recv_mini_commit(commit, pack->privsep_child->ibuf);
+}
+
+const struct got_error *
 got_object_read_commit_privsep(struct got_commit_object **commit,
     struct got_object *obj, int obj_fd, struct got_repository *repo)
 {
@@ -1141,6 +1226,43 @@ got_object_read_commit_privsep(struct got_commit_objec
 	return request_commit(commit, repo, obj, obj_fd);
 }
 
+const struct got_error *
+got_object_read_mini_commit_privsep(struct got_commit_object_mini **commit,
+    struct got_object *obj, int obj_fd, struct got_repository *repo)
+{
+	int imsg_fds[2];
+	pid_t pid;
+	struct imsgbuf *ibuf;
+
+	if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1)
+		return request_mini_commit(commit, repo, obj, obj_fd);
+
+	ibuf = calloc(1, sizeof(*ibuf));
+	if (ibuf == NULL)
+		return got_error_from_errno();
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
+		return got_error_from_errno();
+
+	pid = fork();
+	if (pid == -1)
+		return got_error_from_errno();
+	else if (pid == 0) {
+		exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_COMMIT,
+		    repo->path);
+		/* not reached */
+	}
+
+	close(imsg_fds[1]);
+	repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd =
+	    imsg_fds[0];
+	repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].pid = pid;
+	imsg_init(ibuf, imsg_fds[0]);
+	repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf = ibuf;
+
+	return request_mini_commit(commit, repo, obj, obj_fd);
+}
+
 static const struct got_error *
 request_tree(struct got_tree_object **tree, struct got_repository *repo,
     struct got_object *obj, int fd)
blob - 07d52651602537e5df106ea314f3770df1ffb56f
blob + ebf46135eb8eed76cb6a8e760c20294fcdb3cc06
--- lib/object_parse.c
+++ lib/object_parse.c
@@ -42,10 +42,10 @@
 
 #include "got_lib_sha1.h"
 #include "got_lib_delta.h"
-#include "got_lib_privsep.h"
-#include "got_lib_pack.h"
 #include "got_lib_inflate.h"
 #include "got_lib_object.h"
+#include "got_lib_privsep.h"
+#include "got_lib_pack.h"
 #include "got_lib_object_cache.h"
 #include "got_lib_repository.h"
 
@@ -102,6 +102,24 @@ got_object_close(struct got_object *obj)
 	free(obj);
 }
 
+const struct got_error *
+got_object_qid_alloc_partial(struct got_object_qid **qid)
+{
+	const struct got_error *err = NULL;
+
+	*qid = malloc(sizeof(**qid));
+	if (*qid == NULL)
+		return got_error_from_errno();
+
+	(*qid)->id = malloc(sizeof(*((*qid)->id)));
+	if ((*qid)->id == NULL) {
+		err = got_error_from_errno();
+		got_object_qid_free(*qid);
+		*qid = NULL;
+	}
+	return err;
+}
+
 void
 got_object_qid_free(struct got_object_qid *qid)
 {
@@ -128,6 +146,25 @@ got_object_commit_alloc_partial(void)
 	return commit;
 }
 
+struct got_commit_object_mini *
+got_object_mini_commit_alloc_partial(void)
+{
+	struct got_commit_object_mini *commit;
+
+	commit = calloc(1, sizeof(*commit));
+	if (commit == NULL)
+		return NULL;
+	commit->tree_id = calloc(1, sizeof(*commit->tree_id));
+	if (commit->tree_id == NULL) {
+		free(commit);
+		return NULL;
+	}
+
+	SIMPLEQ_INIT(&commit->parent_ids);
+
+	return commit;
+}
+
 const struct got_error *
 got_object_commit_add_parent(struct got_commit_object *commit,
     const char *id_str)
@@ -135,17 +172,34 @@ got_object_commit_add_parent(struct got_commit_object 
 	const struct got_error *err = NULL;
 	struct got_object_qid *qid;
 
-	qid = malloc(sizeof(*qid));
-	if (qid == NULL)
-		return got_error_from_errno();
-
-	qid->id = malloc(sizeof(*qid->id));
-	if (qid->id == NULL) {
-		err = got_error_from_errno();
-		got_object_qid_free(qid);
+	err = got_object_qid_alloc_partial(&qid);
+	if (err)
 		return err;
+
+	if (!got_parse_sha1_digest(qid->id->sha1, id_str)) {
+		err = got_error(GOT_ERR_BAD_OBJ_DATA);
+		free(qid->id);
+		free(qid);
+		return err;
 	}
 
+	SIMPLEQ_INSERT_TAIL(&commit->parent_ids, qid, entry);
+	commit->nparents++;
+
+	return NULL;
+}
+
+const struct got_error *
+got_object_mini_commit_add_parent(struct got_commit_object_mini *commit,
+    const char *id_str)
+{
+	const struct got_error *err = NULL;
+	struct got_object_qid *qid;
+
+	err = got_object_qid_alloc_partial(&qid);
+	if (err)
+		return err;
+
 	if (!got_parse_sha1_digest(qid->id->sha1, id_str)) {
 		err = got_error(GOT_ERR_BAD_OBJ_DATA);
 		free(qid->id);
@@ -255,14 +309,30 @@ got_object_commit_close(struct got_commit_object *comm
 	free(commit);
 }
 
+void
+got_object_mini_commit_close(struct got_commit_object_mini *commit)
+{
+	struct got_object_qid *qid;
+
+	while (!SIMPLEQ_EMPTY(&commit->parent_ids)) {
+		qid = SIMPLEQ_FIRST(&commit->parent_ids);
+		SIMPLEQ_REMOVE_HEAD(&commit->parent_ids, entry);
+		got_object_qid_free(qid);
+	}
+
+	free(commit->tree_id);
+	free(commit);
+}
+
 const struct got_error *
-got_object_parse_commit(struct got_commit_object **commit, char *buf, size_t len)
+got_object_parse_commit(struct got_commit_object **commit, char *buf,
+    size_t len)
 {
 	const struct got_error *err = NULL;
 	char *s = buf;
 	size_t tlen;
 	ssize_t remain = (ssize_t)len;
- 
+
 	*commit = got_object_commit_alloc_partial();
 	if (*commit == NULL)
 		return got_error_from_errno();
@@ -375,6 +445,109 @@ done:
 	return err;
 }
 
+const struct got_error *
+got_object_parse_mini_commit(struct got_commit_object_mini **commit, char *buf,
+    size_t len)
+{
+	const struct got_error *err = NULL;
+	char *s = buf;
+	size_t tlen;
+	ssize_t remain = (ssize_t)len;
+
+	*commit = got_object_mini_commit_alloc_partial();
+	if (*commit == NULL)
+		return got_error_from_errno();
+
+	tlen = strlen(GOT_COMMIT_TAG_TREE);
+	if (strncmp(s, GOT_COMMIT_TAG_TREE, tlen) == 0) {
+		remain -= tlen;
+		if (remain < SHA1_DIGEST_STRING_LENGTH) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		s += tlen;
+		if (!got_parse_sha1_digest((*commit)->tree_id->sha1, s)) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		remain -= SHA1_DIGEST_STRING_LENGTH;
+		s += SHA1_DIGEST_STRING_LENGTH;
+	} else {
+		err = got_error(GOT_ERR_BAD_OBJ_DATA);
+		goto done;
+	}
+
+	tlen = strlen(GOT_COMMIT_TAG_PARENT);
+	while (strncmp(s, GOT_COMMIT_TAG_PARENT, tlen) == 0) {
+		remain -= tlen;
+		if (remain < SHA1_DIGEST_STRING_LENGTH) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		s += tlen;
+		err = got_object_mini_commit_add_parent(*commit, s);
+		if (err)
+			goto done;
+
+		remain -= SHA1_DIGEST_STRING_LENGTH;
+		s += SHA1_DIGEST_STRING_LENGTH;
+	}
+
+	tlen = strlen(GOT_COMMIT_TAG_AUTHOR);
+	if (strncmp(s, GOT_COMMIT_TAG_AUTHOR, tlen) == 0) {
+		char *p;
+		size_t slen;
+
+		remain -= tlen;
+		if (remain <= 0) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		s += tlen;
+		p = strchr(s, '\n');
+		if (p == NULL) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		*p = '\0';
+		slen = strlen(s);
+		s += slen + 1;
+		remain -= slen + 1;
+	}
+
+	tlen = strlen(GOT_COMMIT_TAG_COMMITTER);
+	if (strncmp(s, GOT_COMMIT_TAG_COMMITTER, tlen) == 0) {
+		char *p;
+		size_t slen;
+
+		remain -= tlen;
+		if (remain <= 0) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		s += tlen;
+		p = strchr(s, '\n');
+		if (p == NULL) {
+			err = got_error(GOT_ERR_BAD_OBJ_DATA);
+			goto done;
+		}
+		*p = '\0';
+		slen = strlen(s);
+		err = parse_commit_time(&(*commit)->tm_committer, s);
+		if (err)
+			goto done;
+		s += slen + 1;
+		remain -= slen + 1;
+	}
+
+done:
+	if (err) {
+		got_object_mini_commit_close(*commit);
+		*commit = NULL;
+	}
+	return err;
+}
+
 void
 got_object_tree_entry_close(struct got_tree_entry *te)
 {
blob - 2429a9462a3a8c43c3d457557c231213747aec54
blob + e0d4a53bb329a1f39e987e8ef293e4e850ef4b36
--- lib/privsep.c
+++ lib/privsep.c
@@ -214,6 +214,20 @@ got_privsep_send_stop(int fd)
 	return err;
 }
 
+static void
+init_imsg_object(struct got_imsg_object *iobj, struct got_object *obj)
+{
+	memcpy(iobj->id, obj->id.sha1, sizeof(iobj->id));
+	iobj->type = obj->type;
+	iobj->flags = obj->flags;
+	iobj->hdrlen = obj->hdrlen;
+	iobj->size = obj->size;
+	if (iobj->flags & GOT_OBJ_FLAG_PACKED) {
+		iobj->pack_offset = obj->pack_offset;
+		iobj->pack_idx = obj->pack_idx;
+	}
+}
+
 const struct got_error *
 got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd, struct got_object *obj)
 {
@@ -236,15 +250,7 @@ got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd,
 			return got_error(GOT_ERR_OBJ_TYPE);
 		}
 
-		memcpy(iobj.id, obj->id.sha1, sizeof(iobj.id));
-		iobj.type = obj->type;
-		iobj.flags = obj->flags;
-		iobj.hdrlen = obj->hdrlen;
-		iobj.size = obj->size;
-		if (iobj.flags & GOT_OBJ_FLAG_PACKED) {
-			iobj.pack_offset = obj->pack_offset;
-			iobj.pack_idx = obj->pack_idx;
-		}
+		init_imsg_object(&iobj, obj);
 
 		iobjp = &iobj;
 		iobj_size = sizeof(iobj);
@@ -257,6 +263,28 @@ got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd,
 }
 
 const struct got_error *
+got_privsep_send_mini_commit_req(struct imsgbuf *ibuf, int fd,
+    struct got_object *obj)
+{
+	struct got_imsg_object iobj, *iobjp;
+	size_t iobj_size;
+
+	if (obj->type != GOT_OBJ_TYPE_COMMIT)
+		return got_error(GOT_ERR_OBJ_TYPE);
+
+	init_imsg_object(&iobj, obj);
+
+	iobjp = &iobj;
+	iobj_size = sizeof(iobj);
+
+	if (imsg_compose(ibuf, GOT_IMSG_MINI_COMMIT_REQUEST, 0, 0, fd,
+	    iobjp, iobj_size) == -1)
+		return got_error_from_errno();
+
+	return flush_imsg(ibuf);
+}
+
+const struct got_error *
 got_privsep_send_blob_req(struct imsgbuf *ibuf, int infd)
 {
 	if (imsg_compose(ibuf, GOT_IMSG_BLOB_REQUEST, 0, 0, infd, NULL, 0)
@@ -456,6 +484,46 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct g
 done:
 	free(buf);
 	return err;
+}
+
+const struct got_error *
+got_privsep_send_mini_commit(struct imsgbuf *ibuf,
+    struct got_commit_object_mini *commit)
+{
+	const struct got_error *err = NULL;
+	struct got_imsg_commit_object_mini icommit;
+	uint8_t *buf;
+	size_t len, total;
+	struct got_object_qid *qid;
+
+	memcpy(icommit.tree_id, commit->tree_id->sha1, sizeof(icommit.tree_id));
+	memcpy(&icommit.tm_committer, &commit->tm_committer,
+	    sizeof(icommit.tm_committer));
+	icommit.nparents = commit->nparents;
+
+	total = sizeof(icommit) + icommit.nparents * SHA1_DIGEST_LENGTH;
+
+	buf = malloc(total);
+	if (buf == NULL)
+		return got_error_from_errno();
+
+	len = 0;
+	memcpy(buf + len, &icommit, sizeof(icommit));
+	len += sizeof(icommit);
+	SIMPLEQ_FOREACH(qid, &commit->parent_ids, entry) {
+		memcpy(buf + len, qid->id, SHA1_DIGEST_LENGTH);
+		len += SHA1_DIGEST_LENGTH;
+	}
+
+	if (imsg_compose(ibuf, GOT_IMSG_MINI_COMMIT, 0, 0, -1,
+	    buf, len) == -1) {
+		err = got_error_from_errno();
+	}
+
+	free(buf);
+	if (err)
+		return err;
+	return flush_imsg(ibuf);
 }
 
 const struct got_error *
@@ -592,17 +660,89 @@ got_privsep_recv_commit(struct got_commit_object **com
 		for (i = 0; i < icommit.nparents; i++) {
 			struct got_object_qid *qid;
 
-			qid = calloc(1, sizeof(*qid));
-			if (qid == NULL) {
-				err = got_error_from_errno();
+			err = got_object_qid_alloc_partial(&qid);
+			if (err)
 				break;
-			}
-			qid->id = calloc(1, sizeof(*qid->id));
-			if (qid->id == NULL) {
-				err = got_error_from_errno();
-				free(qid);
+
+			memcpy(qid->id, data + len + i * SHA1_DIGEST_LENGTH,
+			    sizeof(*qid->id));
+			SIMPLEQ_INSERT_TAIL(&(*commit)->parent_ids, qid, entry);
+			(*commit)->nparents++;
+		}
+		break;
+	default:
+		err = got_error(GOT_ERR_PRIVSEP_MSG);
+		break;
+	}
+
+	imsg_free(&imsg);
+
+	return err;
+}
+
+const struct got_error *
+got_privsep_recv_mini_commit(struct got_commit_object_mini **commit,
+    struct imsgbuf *ibuf)
+{
+	const struct got_error *err = NULL;
+	struct imsg imsg;
+	struct got_imsg_commit_object_mini icommit;
+	size_t len, datalen;
+	int i;
+	const size_t min_datalen =
+	    MIN(sizeof(struct got_imsg_error),
+	    sizeof(struct got_imsg_commit_object_mini));
+	uint8_t *data;
+
+	*commit = NULL;
+
+	err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
+	if (err)
+		return err;
+
+	data = imsg.data;
+	datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+	len = 0;
+
+	switch (imsg.hdr.type) {
+	case GOT_IMSG_ERROR:
+		err = recv_imsg_error(&imsg, datalen);
+		break;
+	case GOT_IMSG_MINI_COMMIT:
+		if (datalen < sizeof(icommit)) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			break;
+		}
+
+		memcpy(&icommit, data, sizeof(icommit));
+		if (datalen != sizeof(icommit) +
+		    icommit.nparents * SHA1_DIGEST_LENGTH) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			break;
+		}
+		if (icommit.nparents < 0) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			break;
+		}
+		len += sizeof(icommit);
+
+		*commit = got_object_mini_commit_alloc_partial();
+		if (*commit == NULL) {
+			err = got_error_from_errno();
+			break;
+		}
+
+		memcpy((*commit)->tree_id->sha1, icommit.tree_id,
+		    SHA1_DIGEST_LENGTH);
+		memcpy(&(*commit)->tm_committer, &icommit.tm_committer,
+		    sizeof((*commit)->tm_committer));
+
+		for (i = 0; i < icommit.nparents; i++) {
+			struct got_object_qid *qid;
+
+			err = got_object_qid_alloc_partial(&qid);
+			if (err)
 				break;
-			}
 
 			memcpy(qid->id, data + len + i * SHA1_DIGEST_LENGTH,
 			    sizeof(*qid->id));
blob - f6b5435605333d42433c5981a64efdc3cb4b18e6
blob + 49187ef259affaaff4c947f46d12fb23afb35738
--- libexec/got-read-commit/got-read-commit.c
+++ libexec/got-read-commit/got-read-commit.c
@@ -39,38 +39,67 @@
 #include "got_lib_privsep.h"
 
 static const struct got_error *
-read_commit_object(struct got_commit_object **commit, struct got_object *obj,
-    FILE *f)
+read_commit_data(uint8_t **p, size_t *len, struct got_object *obj, FILE *f)
 {
-	const struct got_error *err = NULL;
-	size_t len;
-	uint8_t *p;
+	const struct got_error *err;
 
 	if (obj->flags & GOT_OBJ_FLAG_PACKED)
-		err = got_read_file_to_mem(&p, &len, f);
+		err = got_read_file_to_mem(p, len, f);
 	else
-		err = got_inflate_to_mem(&p, &len, f);
+		err = got_inflate_to_mem(p, len, f);
 	if (err)
 		return err;
 
-	if (len < obj->hdrlen + obj->size) {
-		err = got_error(GOT_ERR_BAD_OBJ_DATA);
-		goto done;
+	if (*len < obj->hdrlen + obj->size) {
+		free(*p);
+		*p = NULL;
+		*len = 0;
+		return got_error(GOT_ERR_BAD_OBJ_DATA);
 	}
 
 	/* Skip object header. */
-	len -= obj->hdrlen;
+	*len -= obj->hdrlen;
+	return NULL;
+}
+
+static const struct got_error *
+read_commit_object(struct got_commit_object **commit, struct got_object *obj,
+    FILE *f)
+{
+	const struct got_error *err;
+	uint8_t *p;
+	size_t len;
+
+	err = read_commit_data(&p, &len, obj, f);
+	if (err)
+		return err;
+
 	err = got_object_parse_commit(commit, p + obj->hdrlen, len);
 	free(p);
-done:
 	return err;
 }
 
+static const struct got_error *
+read_commit_object_mini(struct got_commit_object_mini **commit,
+    struct got_object *obj, FILE *f)
+{
+	const struct got_error *err;
+	size_t len;
+	uint8_t *p;
+
+	err = read_commit_data(&p, &len, obj, f);
+	if (err)
+		return err;
+
+	err = got_object_parse_mini_commit(commit, p + obj->hdrlen, len);
+	free(p);
+	return err;
+}
+
 int
 main(int argc, char *argv[])
 {
 	const struct got_error *err = NULL;
-	struct got_commit_object *commit = NULL;
 	struct imsgbuf ibuf;
 	size_t datalen;
 
@@ -90,6 +119,7 @@ main(int argc, char *argv[])
 		struct got_imsg_object iobj;
 		FILE *f = NULL;
 		struct got_object *obj = NULL;
+		int mini = 0;
 	
 		err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 		if (err) {
@@ -101,9 +131,16 @@ main(int argc, char *argv[])
 		if (imsg.hdr.type == GOT_IMSG_STOP)
 			break;
 
-		if (imsg.hdr.type != GOT_IMSG_COMMIT_REQUEST) {
-			err = got_error(GOT_ERR_PRIVSEP_MSG);
-			goto done;
+		switch (imsg.hdr.type) {
+			case GOT_IMSG_COMMIT_REQUEST:
+				mini = 0;
+				break;
+			case GOT_IMSG_MINI_COMMIT_REQUEST:
+				mini = 1;
+				break;
+			default:
+				err = got_error(GOT_ERR_PRIVSEP_MSG);
+				goto done;
 		}
 
 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
@@ -139,11 +176,21 @@ main(int argc, char *argv[])
 			goto done;
 		}
 
-		err = read_commit_object(&commit, obj, f);
-		if (err)
-			goto done;
-
-		err = got_privsep_send_commit(&ibuf, commit);
+		if (mini) {
+			struct got_commit_object_mini *commit;
+			err = read_commit_object_mini(&commit, obj, f);
+			if (err)
+				goto done;
+			err = got_privsep_send_mini_commit(&ibuf, commit);
+			got_object_mini_commit_close(commit);
+		} else {
+			struct got_commit_object *commit;
+			err = read_commit_object(&commit, obj, f);
+			if (err)
+				goto done;
+			err = got_privsep_send_commit(&ibuf, commit);
+			got_object_commit_close(commit);
+		}
 done:
 		if (f)
 			fclose(f);
blob - 010b14b5519db260c50522b9ffb8d93182af1675
blob + 1a4046e49b76e09595fd6cb02c2779592713c7c2
--- libexec/got-read-pack/got-read-pack.c
+++ libexec/got-read-pack/got-read-pack.c
@@ -134,6 +134,44 @@ commit_request(struct imsg *imsg, struct imsgbuf *ibuf
 	if (obj)
 		got_object_close(obj);
 	got_object_commit_close(commit);
+	if (err) {
+		if (err->code == GOT_ERR_PRIVSEP_PIPE)
+			err = NULL;
+		else
+			got_privsep_send_error(ibuf, err);
+	}
+
+	return err;
+}
+
+static const struct got_error *
+mini_commit_request(struct imsg *imsg, struct imsgbuf *ibuf,
+    struct got_pack *pack, struct got_packidx *packidx,
+    struct got_object_cache *objcache)
+{
+	const struct got_error *err = NULL;
+	struct got_object *obj = NULL;
+	struct got_commit_object_mini *commit = NULL;
+	uint8_t *buf;
+	size_t len;
+
+	err = get_object(&obj, imsg, ibuf, pack, packidx, objcache,
+	    GOT_OBJ_TYPE_COMMIT);
+	if (err)
+		return err;
+
+	err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
+	if (err)
+		return err;
+
+	obj->size = len;
+	err = got_object_parse_mini_commit(&commit, buf, len);
+	free(buf);
+
+	err = got_privsep_send_mini_commit(ibuf, commit);
+	if (obj)
+		got_object_close(obj);
+	got_object_mini_commit_close(commit);
 	if (err) {
 		if (err->code == GOT_ERR_PRIVSEP_PIPE)
 			err = NULL;
@@ -464,6 +502,10 @@ main(int argc, char *argv[])
 			err = commit_request(&imsg, &ibuf, pack, packidx,
 			    &objcache);
 			break;
+		case GOT_IMSG_MINI_COMMIT_REQUEST:
+			err = mini_commit_request(&imsg, &ibuf, pack, packidx,
+			    &objcache);
+			break;
 		case GOT_IMSG_TREE_REQUEST:
 			err = tree_request(&imsg, &ibuf, pack, packidx,
 			   &objcache);