Commit Diff


commit - 5767055949fa7c49469611a514c2f4e3ae77c5e1
commit + 15a949835c36ceb581fc115aff744dbb30b12918
blob - 9ca1e6c6f71588c3806a731999ac91937c63c1f2
blob + 4f7d23771ac7850de8807514c25be47cc3ceb7fc
--- got/got.c
+++ got/got.c
@@ -416,9 +416,9 @@ print_commit(struct got_commit_object *commit, struct 
 }
 
 static const struct got_error *
-print_commits(struct got_object *root_obj, struct got_object_id *root_id,
-    struct got_repository *repo, char *path, int show_patch, int diff_context,
-    int limit, int first_parent_traversal)
+print_commits(struct got_object_id *root_id, struct got_repository *repo,
+    char *path, int show_patch, int diff_context, int limit,
+    int first_parent_traversal)
 {
 	const struct got_error *err;
 	struct got_commit_graph *graph;
@@ -480,8 +480,8 @@ cmd_log(int argc, char *argv[])
 {
 	const struct got_error *error;
 	struct got_repository *repo = NULL;
+	struct got_commit_object *commit = NULL;
 	struct got_object_id *id = NULL;
-	struct got_object *obj = NULL;
 	char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL;
 	char *start_commit = NULL;
 	int diff_context = 3, ch;
@@ -565,7 +565,7 @@ cmd_log(int argc, char *argv[])
 		got_ref_close(head_ref);
 		if (error != NULL)
 			return error;
-		error = got_object_open(&obj, repo, id);
+		error = got_object_open_as_commit(&commit, repo, id);
 	} else {
 		struct got_reference *ref;
 		error = got_ref_open(&ref, repo, start_commit);
@@ -574,26 +574,19 @@ cmd_log(int argc, char *argv[])
 			got_ref_close(ref);
 			if (error != NULL)
 				return error;
-			error = got_object_open(&obj, repo, id);
+			error = got_object_open_as_commit(&commit, repo, id);
 			if (error != NULL)
 				return error;
 		}
-		if (obj == NULL) {
-			error = got_object_open_by_id_str(&obj, repo,
+		if (commit == NULL) {
+			error = got_object_resolve_id_str(&id, repo,
 			    start_commit);
 			if (error != NULL)
 				return error;
-			id = got_object_id_dup(got_object_get_id(obj));
-			if (id == NULL)
-				error = got_error_from_errno();
 		}
 	}
 	if (error != NULL)
 		goto done;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
-		error = got_error(GOT_ERR_OBJ_TYPE);
-		goto done;
-	}
 
 	error = got_repo_map_path(&in_repo_path, repo, path, 1);
 	if (error != NULL)
@@ -603,14 +596,12 @@ cmd_log(int argc, char *argv[])
 		path = in_repo_path;
 	}
 
-	error = print_commits(obj, id, repo, path, show_patch,
+	error = print_commits(id, repo, path, show_patch,
 	    diff_context, limit, first_parent_traversal);
 done:
 	free(path);
 	free(repo_path);
 	free(cwd);
-	if (obj)
-		got_object_close(obj);
 	free(id);
 	if (repo) {
 		const struct got_error *repo_error;
@@ -634,9 +625,10 @@ cmd_diff(int argc, char *argv[])
 {
 	const struct got_error *error;
 	struct got_repository *repo = NULL;
-	struct got_object *obj1 = NULL, *obj2 = NULL;
 	char *repo_path = NULL;
-	char *obj_id_str1 = NULL, *obj_id_str2 = NULL;
+	struct got_object_id *id1 = NULL, *id2 = NULL;
+	char *id_str1 = NULL, *id_str2 = NULL;
+	int type1, type2;
 	int diff_context = 3, ch;
 	const char *errstr;
 
@@ -668,14 +660,14 @@ cmd_diff(int argc, char *argv[])
 		repo_path = getcwd(NULL, 0);
 		if (repo_path == NULL)
 			return got_error_from_errno();
-		obj_id_str1 = argv[0];
-		obj_id_str2 = argv[1];
+		id_str1 = argv[0];
+		id_str2 = argv[1];
 	} else if (argc == 3) {
 		repo_path = realpath(argv[0], NULL);
 		if (repo_path == NULL)
 			return got_error_from_errno();
-		obj_id_str1 = argv[1];
-		obj_id_str2 = argv[2];
+		id_str1 = argv[1];
+		id_str2 = argv[2];
 	} else
 		usage_diff();
 
@@ -684,32 +676,40 @@ cmd_diff(int argc, char *argv[])
 	if (error != NULL)
 		goto done;
 
-	error = got_object_open_by_id_str(&obj1, repo, obj_id_str1);
+	error = got_object_resolve_id_str(&id1, repo, id_str1);
 	if (error)
 		goto done;
 
-	error = got_object_open_by_id_str(&obj2, repo, obj_id_str2);
+	error = got_object_resolve_id_str(&id2, repo, id_str2);
 	if (error)
 		goto done;
 
-	if (got_object_get_type(obj1) != got_object_get_type(obj2)) {
+	error = got_object_get_type(&type1, repo, id1);
+	if (error)
+		goto done;
+
+	error = got_object_get_type(&type2, repo, id2);
+	if (error)
+		goto done;
+
+	if (type1 != type2) {
 		error = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
 
-	switch (got_object_get_type(obj1)) {
+	switch (type1) {
 	case GOT_OBJ_TYPE_BLOB:
-		error = got_diff_objects_as_blobs(obj1, obj2, NULL, NULL,
+		error = got_diff_objects_as_blobs(id1, id2, NULL, NULL,
 		    diff_context, repo, stdout);
 		break;
 	case GOT_OBJ_TYPE_TREE:
-		error = got_diff_objects_as_trees(obj1, obj2, "", "",
+		error = got_diff_objects_as_trees(id1, id2, "", "",
 		    diff_context, repo, stdout);
 		break;
 	case GOT_OBJ_TYPE_COMMIT:
-		printf("diff %s %s\n", obj_id_str1 ? obj_id_str1 : "/dev/null",
-		    obj_id_str2);
-		error = got_diff_objects_as_commits(obj1, obj2, diff_context,
+		printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null",
+		    id_str2);
+		error = got_diff_objects_as_commits(id1, id2, diff_context,
 		    repo, stdout);
 		break;
 	default:
@@ -717,10 +717,8 @@ cmd_diff(int argc, char *argv[])
 	}
 
 done:
-	if (obj1)
-		got_object_close(obj1);
-	if (obj2)
-		got_object_close(obj2);
+	free(id1);
+	free(id2);
 	if (repo) {
 		const struct got_error *repo_error;
 		repo_error = got_repo_close(repo);
@@ -809,14 +807,10 @@ cmd_blame(int argc, char *argv[])
 		if (error != NULL)
 			goto done;
 	} else {
-		struct got_object *obj;
-		error = got_object_open_by_id_str(&obj, repo, commit_id_str);
+		error = got_object_resolve_id_str(&commit_id, repo,
+		    commit_id_str);
 		if (error != NULL)
 			goto done;
-		commit_id = got_object_id_dup(got_object_get_id(obj));
-		if (commit_id == NULL)
-			error = got_error_from_errno();
-		got_object_close(obj);
 	}
 
 	error = got_blame(in_repo_path, commit_id, repo, stdout);
@@ -969,14 +963,10 @@ cmd_tree(int argc, char *argv[])
 		if (error != NULL)
 			goto done;
 	} else {
-		struct got_object *obj;
-		error = got_object_open_by_id_str(&obj, repo, commit_id_str);
+		error = got_object_resolve_id_str(&commit_id, repo,
+		    commit_id_str);
 		if (error != NULL)
 			goto done;
-		commit_id = got_object_id_dup(got_object_get_id(obj));
-		if (commit_id == NULL)
-			error = got_error_from_errno();
-		got_object_close(obj);
 	}
 
 	error = print_tree(in_repo_path, commit_id, show_ids, repo);
blob - a817a1eabed26be1253b9c113d07a6679a76376b
blob + 01e0ac643704c52d2defe4e6e2bffdc0b8b5f8e4
--- include/got_diff.h
+++ include/got_diff.h
@@ -42,8 +42,8 @@ const struct got_error *got_diff_tree(struct got_tree_
  * The number of context lines to show in the diff must be specified as well.
  * Write unified diff text to the provided output FILE.
  */
-const struct got_error *got_diff_objects_as_blobs(struct got_object *,
-    struct got_object *, const char *, const char *, int,
+const struct got_error *got_diff_objects_as_blobs(struct got_object_id *,
+    struct got_object_id *, const char *, const char *, int,
     struct got_repository *, FILE *);
 
 /*
@@ -53,15 +53,15 @@ const struct got_error *got_diff_objects_as_blobs(stru
  * The number of context lines to show in diffs must be specified.
  * Write unified diff text to the provided output FILE.
  */
-const struct got_error *got_diff_objects_as_trees(struct got_object *,
-    struct got_object *, char *, char *, int, struct got_repository *, FILE *);
+const struct got_error *got_diff_objects_as_trees(struct got_object_id *,
+    struct got_object_id *, char *, char *, int, struct got_repository *, FILE *);
 
 /*
  * Diff two objects, assuming both objects are commits.
  * The number of context lines to show in diffs must be specified.
  * Write unified diff text to the provided output FILE.
  */
-const struct got_error *got_diff_objects_as_commits(struct got_object *,
-    struct got_object *, int, struct got_repository *, FILE *);
+const struct got_error *got_diff_objects_as_commits(struct got_object_id *,
+    struct got_object_id *, int, struct got_repository *, FILE *);
 
 #define GOT_DIFF_MAX_CONTEXT	64
blob - 17bb86dfcb85bb18275fcb5dea4c782859da9699
blob + 514355200012b8f3306f409556261bae2b9822f8
--- include/got_object.h
+++ include/got_object.h
@@ -46,8 +46,7 @@ const struct got_error *got_object_qid_alloc(struct go
     struct got_object_id *);
 void got_object_qid_free(struct got_object_qid *);
 
-/* A generic object. Used as a handle which holds an ID and an object type. */
-struct got_object;
+/* Object types. */
 #define GOT_OBJ_TYPE_COMMIT		1
 #define GOT_OBJ_TYPE_TREE		2
 #define GOT_OBJ_TYPE_BLOB		3
@@ -77,19 +76,6 @@ int got_object_id_cmp(const struct got_object_id *,
 struct got_object_id *got_object_id_dup(struct got_object_id *);
 
 /*
- * Get a newly allocated copy of an object's ID.
- * The caller must treat the ID as read-only and must not call free(3) on it.
- * Use got_object_id_dup() to get a writable copy.
- */
-struct got_object_id *got_object_get_id(struct got_object *);
-
-/*
- * Get a newly allocated copy of an object's ID string.
- * The caller should dispose of it with free(3).
- */
-const struct got_error *got_object_get_id_str(char **, struct got_object *);
-
-/*
  * Get a newly allocated ID of the object which resides at the specified
  * path in the tree of the specified commit.
  * The caller should dispose of it with free(3).
@@ -102,35 +88,26 @@ got_object_id_by_path(struct got_object_id **, struct 
  * Obtain the type of an object.
  * Returns one of the GOT_OBJ_TYPE_x values (see above).
  */
-int got_object_get_type(struct got_object *);
+const struct got_error *got_object_get_type(int *, struct got_repository *,
+    struct got_object_id *);
 
 /*
- * Attempt to open the object in a repository with the provided ID.
- * Caller must dispose of it with got_object_close().
+ * Attempt to resolve the textual representation of an object ID
+ * to the ID of an existing object in the repository.
+ * The caller should dispose of the ID with free(3).
  */
-const struct got_error *got_object_open(struct got_object **,
-    struct got_repository *, struct got_object_id *);
+const struct got_error *
+got_object_resolve_id_str(struct got_object_id **, struct got_repository *,
+    const char *);
 
 /*
- * Attempt to map the provided ID string to an object ID and then
- * attempt to open the object in a repository with this ID.
- * The form of an ID string depends on the hash function used by the
- * repository format (currently SHA1).
- * Caller must dispose of the object with got_object_close().
- */
-const struct got_error *got_object_open_by_id_str(struct got_object **,
-    struct got_repository *, const char *);
-
-/* Dispose of an object. */
-void got_object_close(struct got_object *);
-
-/*
  * Attempt to open a commit object in a repository.
  * The provided object must be of type GOT_OBJ_TYPE_COMMIT.
  * The caller must dispose of the commit with got_object_commit_close().
  */
-const struct got_error *got_object_commit_open(struct got_commit_object **,
-    struct got_repository *, struct got_object *);
+const struct got_error *
+got_object_open_as_commit(struct got_commit_object **,
+    struct got_repository *, struct got_object_id *);
 
 /* Dispose of a commit object. */
 void got_object_commit_close(struct got_commit_object *);
@@ -171,8 +148,9 @@ const char *got_object_commit_get_logmsg(struct got_co
  * The provided object must be of type GOT_OBJ_TYPE_TREE.
  * The caller must dispose of the tree with got_object_tree_close().
  */
-const struct got_error *got_object_tree_open(struct got_tree_object **,
-    struct got_repository *, struct got_object *);
+const struct got_error *
+got_object_open_as_tree(struct got_tree_object **,
+    struct got_repository *, struct got_object_id *);
 
 /* Dispose of a tree object. */
 void got_object_tree_close(struct got_tree_object *);
@@ -196,8 +174,9 @@ const struct got_error *got_object_tree_path_changed(i
  * The size_t argument specifies the block size of an associated read buffer.
  * The caller must dispose of the blob with got_object_blob_close().
  */
-const struct got_error *got_object_blob_open(struct got_blob_object **,
-    struct got_repository *, struct got_object *, size_t);
+const struct got_error *
+got_object_open_as_blob(struct got_blob_object **,
+    struct got_repository *, struct got_object_id *, size_t);
 
 /* Dispose of a blob object. */
 void got_object_blob_close(struct got_blob_object *);
@@ -246,23 +225,11 @@ const struct got_error *got_object_blob_dump_to_file(s
  * The provided object must be of type GOT_OBJ_TYPE_TAG.
  * The caller must dispose of the tree with got_object_tag_close().
  */
-const struct got_error *got_object_tag_open(struct got_tag_object **,
-    struct got_repository *, struct got_object *);
+const struct got_error *got_object_open_as_tag(struct got_tag_object **,
+    struct got_repository *, struct got_object_id *);
 
 /* Dispose of a tag object. */
 void got_object_tag_close(struct got_tag_object *);
 
-const struct got_error *
-got_object_open_as_commit(struct got_commit_object **,
-    struct got_repository *, struct got_object_id *);
-const struct got_error *
-got_object_open_as_tree(struct got_tree_object **,
-    struct got_repository *, struct got_object_id *);
-const struct got_error *
-got_object_open_as_blob(struct got_blob_object **,
-    struct got_repository *, struct got_object_id *, size_t);
-const struct got_error *got_object_open_as_tag(struct got_tag_object **,
-    struct got_repository *, struct got_object_id *);
-
 const struct got_error *got_object_commit_add_parent(struct got_commit_object *,
     const char *);
blob - 977d7f578441bc9814edefb94eb8001344b09deb
blob + e8e4e2b505da78e54c8c0d88c7df21b3aee29442
--- lib/blame.c
+++ lib/blame.c
@@ -203,7 +203,7 @@ blame_commit(struct got_blame *blame, struct got_objec
 	if (err)
 		goto done;
 
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_BLOB) {
+	if (obj->type != GOT_OBJ_TYPE_BLOB) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -228,7 +228,7 @@ blame_commit(struct got_blame *blame, struct got_objec
 	if (err)
 		goto done;
 
-	if (got_object_get_type(pobj) != GOT_OBJ_TYPE_BLOB) {
+	if (pobj->type != GOT_OBJ_TYPE_BLOB) {
 		/*
 		 * Encountered a non-blob at the path (probably a tree).
 		 * Blob's history began in previous commit.
@@ -309,7 +309,7 @@ blame_open(struct got_blame **blamep, const char *path
 	if (err)
 		goto done;
 
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_BLOB) {
+	if (obj->type != GOT_OBJ_TYPE_BLOB) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
blob - 40c9a34cc71199d0d450d917eecec341f671beec
blob + 874c7535c3108bccd764b3e2e206e12189b9aa97
--- lib/delta.c
+++ lib/delta.c
@@ -23,6 +23,7 @@
 #include <zlib.h>
 #include <sha1.h>
 #include <time.h>
+#include <zlib.h>
 
 #include "got_error.h"
 #include "got_repository.h"
@@ -31,6 +32,7 @@
 #include "got_lib_delta.h"
 #include "got_lib_path.h"
 #include "got_lib_inflate.h"
+#include "got_lib_object.h"
 
 #ifndef MIN
 #define	MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
blob - 9af8a526beb32027acfb0c3d1027c8e543a961be
blob + 29d72606d8f28dd96deb06d37531e5db5e1c99ab
--- lib/diff.c
+++ lib/diff.c
@@ -32,6 +32,9 @@
 
 #include "got_lib_diff.h"
 #include "got_lib_path.h"
+#include "got_lib_delta.h"
+#include "got_lib_inflate.h"
+#include "got_lib_object.h"
 
 static const struct got_error *
 diff_blobs(struct got_blob_object *blob1, struct got_blob_object *blob2,
@@ -205,7 +208,7 @@ diff_modified_blob(struct got_object_id *id1, struct g
 	err = got_object_open(&obj1, repo, id1);
 	if (err)
 		return err;
-	if (got_object_get_type(obj1) != GOT_OBJ_TYPE_BLOB) {
+	if (obj1->type != GOT_OBJ_TYPE_BLOB) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -213,7 +216,7 @@ diff_modified_blob(struct got_object_id *id1, struct g
 	err = got_object_open(&obj2, repo, id2);
 	if (err)
 		goto done;
-	if (got_object_get_type(obj2) != GOT_OBJ_TYPE_BLOB) {
+	if (obj2->type != GOT_OBJ_TYPE_BLOB) {
 		err = got_error(GOT_ERR_BAD_OBJ_DATA);
 		goto done;
 	}
@@ -276,7 +279,7 @@ diff_added_tree(struct got_object_id *id, const char *
 	if (err)
 		goto done;
 
-	if (got_object_get_type(treeobj) != GOT_OBJ_TYPE_TREE) {
+	if (treeobj->type != GOT_OBJ_TYPE_TREE) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -311,7 +314,7 @@ diff_modified_tree(struct got_object_id *id1, struct g
 	if (err)
 		goto done;
 
-	if (got_object_get_type(treeobj1) != GOT_OBJ_TYPE_TREE) {
+	if (treeobj1->type != GOT_OBJ_TYPE_TREE) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -320,7 +323,7 @@ diff_modified_tree(struct got_object_id *id1, struct g
 	if (err)
 		goto done;
 
-	if (got_object_get_type(treeobj2) != GOT_OBJ_TYPE_TREE) {
+	if (treeobj2->type != GOT_OBJ_TYPE_TREE) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -360,7 +363,7 @@ diff_deleted_tree(struct got_object_id *id, const char
 	if (err)
 		goto done;
 
-	if (got_object_get_type(treeobj) != GOT_OBJ_TYPE_TREE) {
+	if (treeobj->type != GOT_OBJ_TYPE_TREE) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -526,23 +529,23 @@ got_diff_tree(struct got_tree_object *tree1, struct go
 }
 
 const struct got_error *
-got_diff_objects_as_blobs(struct got_object *obj1, struct got_object *obj2,
+got_diff_objects_as_blobs(struct got_object_id *id1, struct got_object_id *id2,
     const char *label1, const char *label2, int diff_context,
     struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_blob_object *blob1 = NULL, *blob2 = NULL;
 
-	if (obj1 == NULL && obj2 == NULL)
+	if (id1 == NULL && id2 == NULL)
 		return got_error(GOT_ERR_NO_OBJ);
 
-	if (obj1) {
-		err = got_object_blob_open(&blob1, repo, obj1, 8192);
+	if (id1) {
+		err = got_object_open_as_blob(&blob1, repo, id1, 8192);
 		if (err)
 			goto done;
 	}
-	if (obj2) {
-		err = got_object_blob_open(&blob2, repo, obj2, 8192);
+	if (id2) {
+		err = got_object_open_as_blob(&blob2, repo, id2, 8192);
 		if (err)
 			goto done;
 	}
@@ -557,23 +560,23 @@ done:
 }
 
 const struct got_error *
-got_diff_objects_as_trees(struct got_object *obj1, struct got_object *obj2,
+got_diff_objects_as_trees(struct got_object_id *id1, struct got_object_id *id2,
     char *label1, char *label2, int diff_context, struct got_repository *repo,
     FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_tree_object *tree1 = NULL, *tree2 = NULL;
 
-	if (obj1 == NULL && obj2 == NULL)
+	if (id1 == NULL && id2 == NULL)
 		return got_error(GOT_ERR_NO_OBJ);
 
-	if (obj1) {
-		err = got_object_tree_open(&tree1, repo, obj1);
+	if (id1) {
+		err = got_object_open_as_tree(&tree1, repo, id1);
 		if (err)
 			goto done;
 	}
-	if (obj2) {
-		err = got_object_tree_open(&tree2, repo, obj2);
+	if (id2) {
+		err = got_object_open_as_tree(&tree2, repo, id2);
 		if (err)
 			goto done;
 	}
@@ -588,41 +591,31 @@ done:
 }
 
 const struct got_error *
-got_diff_objects_as_commits(struct got_object *obj1, struct got_object *obj2,
-    int diff_context, struct got_repository *repo, FILE *outfile)
+got_diff_objects_as_commits(struct got_object_id *id1,
+    struct got_object_id *id2, int diff_context,
+    struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_commit_object *commit1 = NULL, *commit2 = NULL;
-	struct got_object *tree_obj1  = NULL, *tree_obj2 = NULL;
 
-	if (obj2 == NULL)
+	if (id2 == NULL)
 		return got_error(GOT_ERR_NO_OBJ);
 
-	if (obj1) {
-		err = got_object_commit_open(&commit1, repo, obj1);
+	if (id1) {
+		err = got_object_open_as_commit(&commit1, repo, id1);
 		if (err)
 			goto done;
-		err = got_object_open(&tree_obj1, repo,
-		    got_object_commit_get_tree_id(commit1));
-		if (err)
-			goto done;
 	}
 
-	err = got_object_commit_open(&commit2, repo, obj2);
+	err = got_object_open_as_commit(&commit2, repo, id2);
 	if (err)
 		goto done;
-	err = got_object_open(&tree_obj2, repo,
-	    got_object_commit_get_tree_id(commit2));
-	if (err)
-		goto done;
 
-	err = got_diff_objects_as_trees(tree_obj1, tree_obj2, "", "",
-	    diff_context, repo, outfile);
+	err = got_diff_objects_as_trees(
+	    commit1 ? got_object_commit_get_tree_id(commit1) : NULL,
+	    got_object_commit_get_tree_id(commit2), "", "", diff_context, repo,
+	    outfile);
 done:
-	if (tree_obj1)
-		got_object_close(tree_obj1);
-	if (tree_obj2)
-		got_object_close(tree_obj2);
 	if (commit1)
 		got_object_commit_close(commit1);
 	if (commit2)
blob - 7bcbdfd39b328a04433e376dbf7471f0e48c4482
blob + 87f0ab97317782cc93168da4c232f27d71c14646
--- lib/got_lib_object.h
+++ lib/got_lib_object.h
@@ -20,6 +20,7 @@ struct got_object_id {
 
 struct got_object {
 	int type;
+
 	int flags;
 #define GOT_OBJ_FLAG_PACKED		0x01
 #define GOT_OBJ_FLAG_DELTIFIED		0x02
@@ -73,3 +74,19 @@ struct got_tag_object {
 	char *tagmsg;
 	int refcnt;		/* > 0 if open and/or cached */
 };
+
+struct got_object_id *got_object_get_id(struct got_object *);
+const struct got_error *got_object_get_id_str(char **, struct got_object *);
+const struct got_error *got_object_open(struct got_object **,
+    struct got_repository *, struct got_object_id *);
+const struct got_error *got_object_open_by_id_str(struct got_object **,
+    struct got_repository *, const char *);
+void got_object_close(struct got_object *);
+const struct got_error *got_object_commit_open(struct got_commit_object **,
+    struct got_repository *, struct got_object *);
+const struct got_error *got_object_tree_open(struct got_tree_object **,
+    struct got_repository *, struct got_object *);
+const struct got_error *got_object_blob_open(struct got_blob_object **,
+    struct got_repository *, struct got_object *, size_t);
+const struct got_error *got_object_tag_open(struct got_tag_object **,
+    struct got_repository *, struct got_object *);
blob - d8eaa0694dfff1236a766498a23852ee8d234ee3
blob + 5abbe4fb9abe5e54f998a07a753ac660a1229408
--- lib/object.c
+++ lib/object.c
@@ -42,7 +42,6 @@
 
 #include "got_lib_sha1.h"
 #include "got_lib_delta.h"
-#include "got_lib_pack.h"
 #include "got_lib_path.h"
 #include "got_lib_inflate.h"
 #include "got_lib_object.h"
@@ -50,6 +49,7 @@
 #include "got_lib_object_idcache.h"
 #include "got_lib_object_cache.h"
 #include "got_lib_object_parse.h"
+#include "got_lib_pack.h"
 #include "got_lib_repository.h"
 
 #ifndef MIN
@@ -80,22 +80,31 @@ got_object_get_id_str(char **outbuf, struct got_object
 	return got_object_id_str(outbuf, &obj->id);
 }
 
-int
-got_object_get_type(struct got_object *obj)
+const struct got_error *
+got_object_get_type(int *type, struct got_repository *repo,
+    struct got_object_id *id)
 {
+	const struct got_error *err = NULL;
+	struct got_object *obj;
+
+	err = got_object_open(&obj, repo, id);
+	if (err)
+		return err;
+
 	switch (obj->type) {
 	case GOT_OBJ_TYPE_COMMIT:
 	case GOT_OBJ_TYPE_TREE:
 	case GOT_OBJ_TYPE_BLOB:
 	case GOT_OBJ_TYPE_TAG:
-		return obj->type;
+		*type = obj->type;
+		break;
 	default:
-		abort();
+		err = got_error(GOT_ERR_OBJ_TYPE);
 		break;
 	}
 
-	/* not reached */
-	return 0;
+	got_object_close(obj);
+	return err;
 }
 
 static const struct got_error *
@@ -263,6 +272,25 @@ got_object_open_by_id_str(struct got_object **obj, str
 		return got_error(GOT_ERR_BAD_OBJ_ID_STR);
 
 	return got_object_open(obj, repo, &id);
+}
+
+const struct got_error *
+got_object_resolve_id_str(struct got_object_id **id,
+    struct got_repository *repo, const char *id_str)
+{
+	const struct got_error *err = NULL;
+	struct got_object *obj;
+
+	err = got_object_open_by_id_str(&obj, repo, id_str);
+	if (err)
+		return err;
+
+	*id = got_object_id_dup(got_object_get_id(obj));
+	got_object_close(obj);
+	if (*id == NULL)
+		return got_error_from_errno();
+
+	return NULL;
 }
 
 static const struct got_error *
@@ -326,7 +354,7 @@ got_object_open_as_commit(struct got_commit_object **c
 	err = got_object_open(&obj, repo, id);
 	if (err)
 		return err;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
+	if (obj->type != GOT_OBJ_TYPE_COMMIT) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -425,7 +453,7 @@ got_object_open_as_tree(struct got_tree_object **tree,
 	err = got_object_open(&obj, repo, id);
 	if (err)
 		return err;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_TREE) {
+	if (obj->type != GOT_OBJ_TYPE_TREE) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -612,7 +640,7 @@ got_object_open_as_blob(struct got_blob_object **blob,
 	err = got_object_open(&obj, repo, id);
 	if (err)
 		return err;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_BLOB) {
+	if (obj->type != GOT_OBJ_TYPE_BLOB) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -763,7 +791,7 @@ got_object_open_as_tag(struct got_tag_object **tag,
 	err = got_object_open(&obj, repo, id);
 	if (err)
 		return err;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
+	if (obj->type != GOT_OBJ_TYPE_COMMIT) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
blob - edf8f8d3f1e2d5afcc0926bb3d6edead7609e66b
blob + 21d3471c2b584757cf15d68aad56eb7edd8d3d02
--- lib/object_parse.c
+++ lib/object_parse.c
@@ -42,11 +42,11 @@
 
 #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_object_cache.h"
+#include "got_lib_pack.h"
+#include "got_lib_privsep.h"
 #include "got_lib_repository.h"
 
 #ifndef nitems
blob - 6c51109b82fc94cdee67d253b305f39d6961fcad
blob + 73190458ebaf7433d7caacf33a385c026139d5dd
--- lib/pack.c
+++ lib/pack.c
@@ -37,12 +37,12 @@
 #include "got_opentemp.h"
 
 #include "got_lib_sha1.h"
-#include "got_lib_pack.h"
 #include "got_lib_path.h"
 #include "got_lib_delta.h"
 #include "got_lib_inflate.h"
 #include "got_lib_object.h"
 #include "got_lib_privsep.h"
+#include "got_lib_pack.h"
 
 #ifndef nitems
 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
blob - 20f110b3b35b2536e85df68f177a3d4dde90379c
blob + d74ed85680084b8e192d10eb6f77ade5721e72f1
--- lib/worktree.c
+++ lib/worktree.c
@@ -509,7 +509,7 @@ tree_checkout_entry(struct got_worktree *worktree,
 		progress_path += len;
 	(*progress_cb)(progress_arg, progress_path);
 
-	switch (got_object_get_type(obj)) {
+	switch (obj->type) {
 	case GOT_OBJ_TYPE_BLOB:
 		if (strlen(worktree->path_prefix) >= strlen(path))
 			break;
@@ -623,7 +623,7 @@ got_worktree_checkout_files(struct got_worktree *workt
 	if (err)
 		goto done;
 
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) {
+	if (obj->type != GOT_OBJ_TYPE_COMMIT) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
@@ -637,7 +637,7 @@ got_worktree_checkout_files(struct got_worktree *workt
 	if (err)
 		goto done;
 
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_TREE) {
+	if (obj->type != GOT_OBJ_TYPE_TREE) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
blob - 18bc93be414b53dfc38357b8bfab53aa7227ee28
blob + b06a8e52157c5f52dce914f374c258995ac0dcb8
--- regress/repository/repository_test.c
+++ regress/repository/repository_test.c
@@ -57,7 +57,7 @@ test_printf(char *fmt, ...)
 }
 
 static const struct got_error *
-print_commit_object(struct got_object *, struct got_repository *);
+print_commit_object(struct got_object_id *, struct got_repository *);
 
 static const struct got_error *
 print_parent_commits(struct got_commit_object *commit,
@@ -66,18 +66,10 @@ print_parent_commits(struct got_commit_object *commit,
 	const struct got_object_id_queue *parent_ids;
 	struct got_object_qid *qid;
 	const struct got_error *err = NULL;
-	struct got_object *obj;
 
 	parent_ids = got_object_commit_get_parent_ids(commit);
 	SIMPLEQ_FOREACH(qid, parent_ids, entry) {
-		err = got_object_open(&obj, repo, qid->id);
-		if (err != NULL)
-			return err;
-		if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT)
-			err = got_error(GOT_ERR_OBJ_TYPE);
-		else
-			err = print_commit_object(obj, repo);
-		got_object_close(obj);
+		err = print_commit_object(qid->id, repo);
 		if (err)
 			break;
 	}
@@ -86,7 +78,7 @@ print_parent_commits(struct got_commit_object *commit,
 }
 
 static const struct got_error *
-print_tree_object(struct got_object *obj, char *parent,
+print_tree_object(struct got_object_id *id, char *parent,
     struct got_repository *repo)
 {
 	struct got_tree_object *tree;
@@ -94,13 +86,12 @@ print_tree_object(struct got_object *obj, char *parent
 	struct got_tree_entry *te;
 	const struct got_error *err;
 
-	err = got_object_tree_open(&tree, repo, obj);
+	err = got_object_open_as_tree(&tree, repo, id);
 	if (err != NULL)
 		return err;
 
 	entries = got_object_tree_get_entries(tree);
 	SIMPLEQ_FOREACH(te, &entries->head, entry) {
-		struct got_object *treeobj;
 		char *next_parent;
 		char *hex;
 
@@ -116,30 +107,15 @@ print_tree_object(struct got_object *obj, char *parent
 		test_printf("%s %s/%s\n", hex, parent, te->name);
 		free(hex);
 
-		err = got_object_open(&treeobj, repo, te->id);
-		if (err != NULL)
-			break;
-
-		if (got_object_get_type(treeobj) != GOT_OBJ_TYPE_TREE) {
-			err = got_error(GOT_ERR_OBJ_TYPE);
-			got_object_close(treeobj);
-			break;
-		}
-
 		if (asprintf(&next_parent, "%s/%s", parent, te->name) == -1) {
 			err = got_error_from_errno();
-			got_object_close(treeobj);
 			break;
 		}
 
-		err = print_tree_object(treeobj, next_parent, repo);
+		err = print_tree_object(te->id, next_parent, repo);
 		free(next_parent);
-		if (err) {
-			got_object_close(treeobj);
+		if (err)
 			break;
-		}
-
-		got_object_close(treeobj);
 	}
 
 	got_object_tree_close(tree);
@@ -147,22 +123,24 @@ print_tree_object(struct got_object *obj, char *parent
 }
 
 static const struct got_error *
-print_commit_object(struct got_object *obj, struct got_repository *repo)
+print_commit_object(struct got_object_id *id, struct got_repository *repo)
 {
 	struct got_commit_object *commit;
 	const struct got_object_id_queue *parent_ids;
 	struct got_object_qid *qid;
 	char *buf;
 	const struct got_error *err;
-	struct got_object* treeobj;
+	int obj_type;
 
-	err = got_object_commit_open(&commit, repo, obj);
+	err = got_object_open_as_commit(&commit, repo, id);
 	if (err)
 		return err;
 
-	err = got_object_id_str(&buf, got_object_commit_get_tree_id(commit));
-	if (err)
+	err = got_object_id_str(&buf, id);
+	if (err) {
+		got_object_commit_close(commit);
 		return err;
+	}
 	test_printf("tree: %s\n", buf);
 	free(buf);
 	test_printf("parent%s: ",
@@ -170,8 +148,10 @@ print_commit_object(struct got_object *obj, struct got
 	parent_ids = got_object_commit_get_parent_ids(commit);
 	SIMPLEQ_FOREACH(qid, parent_ids, entry) {
 		err = got_object_id_str(&buf, qid->id);
-		if (err)
+		if (err) {
+			got_object_commit_close(commit);
 			return err;
+		}
 		test_printf("%s\n", buf);
 		free(buf);
 	}
@@ -179,15 +159,14 @@ print_commit_object(struct got_object *obj, struct got
 	test_printf("committer: %s\n", got_object_commit_get_committer(commit));
 	test_printf("log: %s\n", got_object_commit_get_logmsg(commit));
 
-	err = got_object_open(&treeobj, repo,
+	err = got_object_get_type(&obj_type, repo,
 	    got_object_commit_get_tree_id(commit));
-	if (err != NULL)
+	if (err != NULL) {
+		got_object_commit_close(commit);
 		return err;
-	if (got_object_get_type(treeobj) == GOT_OBJ_TYPE_TREE) {
-		print_tree_object(treeobj, "", repo);
-		test_printf("\n");
 	}
-	got_object_close(treeobj);
+	if (obj_type == GOT_OBJ_TYPE_TREE)
+		test_printf("\n");
 
 	err = print_parent_commits(commit, repo);
 	got_object_commit_close(commit);
@@ -202,7 +181,6 @@ repo_read_log(const char *repo_path)
 	struct got_repository *repo;
 	struct got_reference *head_ref;
 	struct got_object_id *id;
-	struct got_object *obj;
 	char *buf;
 
 	err = got_repo_open(&repo, repo_path);
@@ -219,16 +197,9 @@ repo_read_log(const char *repo_path)
 		return 0;
 	test_printf("HEAD is at %s\n", buf);
 	free(buf);
-	err = got_object_open(&obj, repo, id);
-	if (err != NULL || obj == NULL)
-		return 0;
-	if (got_object_get_type(obj) == GOT_OBJ_TYPE_COMMIT) {
-		err = print_commit_object(obj, repo);
-		if (err)
-			return 0;
-	} else
+	err = print_commit_object(id, repo);
+	if (err)
 		return 0;
-	got_object_close(obj);
 	free(id);
 	got_ref_close(head_ref);
 	got_repo_close(repo);
@@ -241,21 +212,18 @@ repo_read_tree(const char *repo_path)
 	const char *tree_sha1 = "6cc96e0e093fb30630ba7f199d0a008b24c6a690";
 	const struct got_error *err;
 	struct got_repository *repo;
-	struct got_object *obj;
+	struct got_object_id *id;
 
 	err = got_repo_open(&repo, repo_path);
 	if (err != NULL || repo == NULL)
 		return 0;
-	err = got_object_open_by_id_str(&obj, repo, tree_sha1);
-	if (err != NULL || obj == NULL)
+	err = got_object_resolve_id_str(&id, repo, tree_sha1);
+	if (err != NULL)
 		return 0;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_TREE)
-		return 0;
 
-	print_tree_object(obj, "", repo);
+	print_tree_object(id, "", repo);
 	test_printf("\n");
 
-	got_object_close(obj);
 	got_repo_close(repo);
 	return (err == NULL);
 }
@@ -266,7 +234,7 @@ repo_read_blob(const char *repo_path)
 	const char *blob_sha1 = "141f5fdc96126c1f4195558560a3c915e3d9b4c3";
 	const struct got_error *err;
 	struct got_repository *repo;
-	struct got_object *obj;
+	struct got_object_id *id;
 	struct got_blob_object *blob;
 	int i;
 	size_t len;
@@ -274,13 +242,10 @@ repo_read_blob(const char *repo_path)
 	err = got_repo_open(&repo, repo_path);
 	if (err != NULL || repo == NULL)
 		return 0;
-	err = got_object_open_by_id_str(&obj, repo, blob_sha1);
-	if (err != NULL || obj == NULL)
+	err = got_object_resolve_id_str(&id, repo, blob_sha1);
+	if (err != NULL)
 		return 0;
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_BLOB)
-		return 0;
-
-	err = got_object_blob_open(&blob, repo, obj, 64);
+	err = got_object_open_as_blob(&blob, repo, id, 64);
 	if (err != NULL)
 		return 0;
 
@@ -296,7 +261,6 @@ repo_read_blob(const char *repo_path)
 	test_printf("\n");
 
 	got_object_blob_close(blob);
-	got_object_close(obj);
 	got_repo_close(repo);
 	return (err == NULL);
 }
@@ -308,8 +272,7 @@ repo_diff_blob(const char *repo_path)
 	const char *blob2_sha1 = "de7eb21b21c7823a753261aadf7cba35c9580fbf";
 	const struct got_error *err;
 	struct got_repository *repo;
-	struct got_object *obj1;
-	struct got_object *obj2;
+	struct got_object_id *id1, *id2;
 	struct got_blob_object *blob1;
 	struct got_blob_object *blob2;
 	FILE *outfile;
@@ -338,22 +301,19 @@ repo_diff_blob(const char *repo_path)
 	if (err != NULL || repo == NULL)
 		return 0;
 
-	err = got_object_open_by_id_str(&obj1, repo, blob1_sha1);
-	if (err != NULL || obj1 == NULL)
-		return 0;
-	if (got_object_get_type(obj1) != GOT_OBJ_TYPE_BLOB)
-		return 0;
-	err = got_object_open_by_id_str(&obj2, repo, blob2_sha1);
-	if (err != NULL || obj2 == NULL)
+	err = got_object_resolve_id_str(&id1, repo, blob1_sha1);
+	if (err != NULL)
 		return 0;
-	if (got_object_get_type(obj2) != GOT_OBJ_TYPE_BLOB)
+
+	err = got_object_resolve_id_str(&id2, repo, blob2_sha1);
+	if (err != NULL)
 		return 0;
 
-	err = got_object_blob_open(&blob1, repo, obj1, 512);
+	err = got_object_open_as_blob(&blob1, repo, id1, 512);
 	if (err != NULL)
 		return 0;
 
-	err = got_object_blob_open(&blob2, repo, obj2, 512);
+	err = got_object_open_as_blob(&blob2, repo, id2, 512);
 	if (err != NULL)
 		return 0;
 
@@ -385,8 +345,6 @@ repo_diff_blob(const char *repo_path)
 
 	got_object_blob_close(blob1);
 	got_object_blob_close(blob2);
-	got_object_close(obj1);
-	got_object_close(obj2);
 	got_repo_close(repo);
 	return (err == NULL);
 }
@@ -398,8 +356,8 @@ repo_diff_tree(const char *repo_path)
 	const char *tree2_sha1 = "4aa8f2933839ff8a8fb3f905a4c232d22c6ff5f3";
 	const struct got_error *err;
 	struct got_repository *repo;
-	struct got_object *obj1;
-	struct got_object *obj2;
+	struct got_object_id *id1;
+	struct got_object_id *id2;
 	struct got_tree_object *tree1;
 	struct got_tree_object *tree2;
 	FILE *outfile;
@@ -408,22 +366,18 @@ repo_diff_tree(const char *repo_path)
 	if (err != NULL || repo == NULL)
 		return 0;
 
-	err = got_object_open_by_id_str(&obj1, repo, tree1_sha1);
-	if (err != NULL || obj1 == NULL)
+	err = got_object_resolve_id_str(&id1, repo, tree1_sha1);
+	if (err != NULL)
 		return 0;
-	if (got_object_get_type(obj1) != GOT_OBJ_TYPE_TREE)
+	err = got_object_resolve_id_str(&id2, repo, tree2_sha1);
+	if (err != NULL)
 		return 0;
-	err = got_object_open_by_id_str(&obj2, repo, tree2_sha1);
-	if (err != NULL || obj2 == NULL)
-		return 0;
-	if (got_object_get_type(obj2) != GOT_OBJ_TYPE_TREE)
-		return 0;
 
-	err = got_object_tree_open(&tree1, repo, obj1);
+	err = got_object_open_as_tree(&tree1, repo, id1);
 	if (err != NULL)
 		return 0;
 
-	err = got_object_tree_open(&tree2, repo, obj2);
+	err = got_object_open_as_tree(&tree2, repo, id2);
 	if (err != NULL)
 		return 0;
 
@@ -439,8 +393,6 @@ repo_diff_tree(const char *repo_path)
 
 	got_object_tree_close(tree1);
 	got_object_tree_close(tree2);
-	got_object_close(obj1);
-	got_object_close(obj2);
 	got_repo_close(repo);
 	return (err == NULL);
 }
blob - e2ca7c7dacf4e7ba9918bc542d28f81a27957444
blob + 6a04b868b4675383fd4f507ceb3a508861fd43e7
--- tog/tog.c
+++ tog/tog.c
@@ -261,7 +261,7 @@ struct tog_view {
 };
 
 static const struct got_error *open_diff_view(struct tog_view *,
-    struct got_object *, struct got_object *, struct got_repository *);
+    struct got_object_id *, struct got_object_id *, struct got_repository *);
 static const struct got_error *show_diff_view(struct tog_view *);
 static const struct got_error *input_diff_view(struct tog_view **,
     struct tog_view **, struct tog_view **, struct tog_view *, int);
@@ -1225,35 +1225,18 @@ open_diff_view_for_commit(struct tog_view **new_view, 
     struct got_repository *repo)
 {
 	const struct got_error *err;
-	struct got_object *obj1 = NULL, *obj2 = NULL;
 	struct got_object_qid *parent_id;
 	struct tog_view *diff_view;
-
-	err = got_object_open(&obj2, repo, commit_id);
-	if (err)
-		return err;
 
 	parent_id = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
-	if (parent_id) {
-		err = got_object_open(&obj1, repo, parent_id->id);
-		if (err)
-			goto done;
-	}
 
 	diff_view = view_open(0, 0, 0, begin_x, TOG_VIEW_DIFF);
-	if (diff_view == NULL) {
-		err = got_error_from_errno();
-		goto done;
-	}
+	if (diff_view == NULL)
+		return got_error_from_errno();
 
-	err = open_diff_view(diff_view, obj1, obj2, repo);
+	err = open_diff_view(diff_view, parent_id->id, commit_id, repo);
 	if (err == NULL)
 		*new_view = diff_view;
-done:
-	if (obj1)
-		got_object_close(obj1);
-	if (obj2)
-		got_object_close(obj2);
 	return err;
 }
 
@@ -1689,20 +1672,11 @@ cmd_log(int argc, char *argv[])
 	if (error != NULL)
 		goto done;
 
-	if (start_commit == NULL) {
+	if (start_commit == NULL)
 		error = get_head_commit_id(&start_id, repo);
-		if (error != NULL)
-			goto done;
-	} else {
-		struct got_object *obj;
-		error = got_object_open_by_id_str(&obj, repo, start_commit);
-		if (error == NULL) {
-			start_id = got_object_id_dup(got_object_get_id(obj));
-			if (start_id == NULL)
-				error = got_error_from_errno();
-				goto done;
-		}
-	}
+	else
+		error = got_object_resolve_id_str(&start_id, repo,
+		    start_commit);
 	if (error != NULL)
 		goto done;
 
@@ -1826,21 +1800,25 @@ get_datestr(time_t *time, char *datebuf)
 }
 
 static const struct got_error *
-write_commit_info(struct got_object *obj, struct got_repository *repo,
+write_commit_info(struct got_object_id *commit_id, struct got_repository *repo,
     FILE *outfile)
 {
 	const struct got_error *err = NULL;
-	char *id_str;
 	char datebuf[26];
-	struct got_commit_object *commit = NULL;
+	struct got_commit_object *commit;
+	char *id_str = NULL;
 	time_t committer_time;
 	const char *author, *committer;
 
-	err = got_object_id_str(&id_str, got_object_get_id(obj));
+	err = got_object_open_as_commit(&commit, repo, commit_id);
 	if (err)
 		return err;
 
-	err = got_object_commit_open(&commit, repo, obj);
+	err = got_object_id_str(&id_str, commit_id);
+	if (err) {
+		err = got_error_from_errno();
+		goto done;
+	}
 
 	if (fprintf(outfile, "commit: %s\n", id_str) < 0) {
 		err = got_error_from_errno();
@@ -1871,8 +1849,7 @@ write_commit_info(struct got_object *obj, struct got_r
 	}
 done:
 	free(id_str);
-	if (commit)
-		got_object_commit_close(commit);
+	got_object_commit_close(commit);
 	return err;
 }
 
@@ -1880,19 +1857,9 @@ static const struct got_error *
 create_diff(struct tog_diff_view_state *s)
 {
 	const struct got_error *err = NULL;
-	struct got_object *obj1 = NULL, *obj2 = NULL;
 	FILE *f = NULL;
+	int obj_type;
 
-	if (s->id1) {
-		err = got_object_open(&obj1, s->repo, s->id1);
-		if (err)
-			return err;
-	}
-
-	err = got_object_open(&obj2, s->repo, s->id2);
-	if (err)
-		goto done;
-
 	f = got_opentemp();
 	if (f == NULL) {
 		err = got_error_from_errno();
@@ -1902,13 +1869,20 @@ create_diff(struct tog_diff_view_state *s)
 		fclose(s->f);
 	s->f = f;
 
-	switch (got_object_get_type(obj1 ? obj1 : obj2)) {
+	if (s->id1)
+		err = got_object_get_type(&obj_type, s->repo, s->id1);
+	else
+		err = got_object_get_type(&obj_type, s->repo, s->id2);
+	if (err)
+		goto done;
+
+	switch (obj_type) {
 	case GOT_OBJ_TYPE_BLOB:
-		err = got_diff_objects_as_blobs(obj1, obj2, NULL, NULL,
+		err = got_diff_objects_as_blobs(s->id1, s->id2, NULL, NULL,
 		    s->diff_context, s->repo, f);
 		break;
 	case GOT_OBJ_TYPE_TREE:
-		err = got_diff_objects_as_trees(obj1, obj2, "", "",
+		err = got_diff_objects_as_trees(s->id1, s->id2, "", "",
 		    s->diff_context, s->repo, f);
 		break;
 	case GOT_OBJ_TYPE_COMMIT: {
@@ -1916,22 +1890,21 @@ create_diff(struct tog_diff_view_state *s)
 		struct got_object_qid *pid;
 		struct got_commit_object *commit2;
 
-		err = got_object_commit_open(&commit2, s->repo, obj2);
+		err = got_object_open_as_commit(&commit2, s->repo, s->id2);
 		if (err)
 			break;
 		/* Show commit info if we're diffing to a parent commit. */
 		parent_ids = got_object_commit_get_parent_ids(commit2);
 		SIMPLEQ_FOREACH(pid, parent_ids, entry) {
-			struct got_object_id *id1 = got_object_get_id(obj1);
-			if (got_object_id_cmp(id1, pid->id) == 0) {
-				write_commit_info(obj2, s->repo, f);
+			if (got_object_id_cmp(s->id1, pid->id) == 0) {
+				write_commit_info(s->id2, s->repo, f);
 				break;
 			}
 		}
 		got_object_commit_close(commit2);
 
-		err = got_diff_objects_as_commits(obj1, obj2, s->diff_context,
-		    s->repo, f);
+		err = got_diff_objects_as_commits(s->id1, s->id2,
+		    s->diff_context, s->repo, f);
 		break;
 	}
 	default:
@@ -1939,34 +1912,38 @@ create_diff(struct tog_diff_view_state *s)
 		break;
 	}
 done:
-	if (obj1)
-		got_object_close(obj1);
-	got_object_close(obj2);
 	if (f)
 		fflush(f);
 	return err;
 }
 
 static const struct got_error *
-open_diff_view(struct tog_view *view, struct got_object *obj1,
-    struct got_object *obj2, struct got_repository *repo)
+open_diff_view(struct tog_view *view, struct got_object_id *id1,
+    struct got_object_id *id2, struct got_repository *repo)
 {
 	const struct got_error *err;
 
-	if (obj1 != NULL && obj2 != NULL &&
-	    got_object_get_type(obj1) != got_object_get_type(obj2))
+	if (id1 != NULL && id2 != NULL) {
+	    int type1, type2;
+	    err = got_object_get_type(&type1, repo, id1);
+	    if (err)
+		return err;
+	    err = got_object_get_type(&type2, repo, id2);
+	    if (err)
+		return err;
+
+	    if (type1 != type2)
 		return got_error(GOT_ERR_OBJ_TYPE);
+	}
 
-	if (obj1) {
-		struct got_object_id *id1;
-		id1 = got_object_id_dup(got_object_get_id(obj1));
-		if (id1 == NULL)
+	if (id1) {
+		view->state.diff.id1 = got_object_id_dup(id1);
+		if (view->state.diff.id1 == NULL)
 			return got_error_from_errno();
-		view->state.diff.id1 = id1;
 	} else
 		view->state.diff.id1 = NULL;
 
-	view->state.diff.id2 = got_object_id_dup(got_object_get_id(obj2));
+	view->state.diff.id2 = got_object_id_dup(id2);
 	if (view->state.diff.id2 == NULL) {
 		free(view->state.diff.id1);
 		view->state.diff.id1 = NULL;
@@ -2099,9 +2076,9 @@ cmd_diff(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
 	struct got_repository *repo = NULL;
-	struct got_object *obj1 = NULL, *obj2 = NULL;
+	struct got_object_id *id1 = NULL, *id2 = NULL;
 	char *repo_path = NULL;
-	char *obj_id_str1 = NULL, *obj_id_str2 = NULL;
+	char *id_str1 = NULL, *id_str2 = NULL;
 	int ch;
 	struct tog_view *view;
 
@@ -2128,14 +2105,14 @@ cmd_diff(int argc, char *argv[])
 		repo_path = getcwd(NULL, 0);
 		if (repo_path == NULL)
 			return got_error_from_errno();
-		obj_id_str1 = argv[0];
-		obj_id_str2 = argv[1];
+		id_str1 = argv[0];
+		id_str2 = argv[1];
 	} else if (argc == 3) {
 		repo_path = realpath(argv[0], NULL);
 		if (repo_path == NULL)
 			return got_error_from_errno();
-		obj_id_str1 = argv[1];
-		obj_id_str2 = argv[2];
+		id_str1 = argv[1];
+		id_str2 = argv[2];
 	} else
 		usage_diff();
 
@@ -2144,11 +2121,11 @@ cmd_diff(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_object_open_by_id_str(&obj1, repo, obj_id_str1);
+	error = got_object_resolve_id_str(&id1, repo, id_str1);
 	if (error)
 		goto done;
 
-	error = got_object_open_by_id_str(&obj2, repo, obj_id_str2);
+	error = got_object_resolve_id_str(&id2, repo, id_str2);
 	if (error)
 		goto done;
 
@@ -2157,16 +2134,12 @@ cmd_diff(int argc, char *argv[])
 		error = got_error_from_errno();
 		goto done;
 	}
-	error = open_diff_view(view, obj1, obj2, repo);
+	error = open_diff_view(view, id1, id2, repo);
 	if (error)
 		goto done;
 	error = view_loop(view);
 done:
 	got_repo_close(repo);
-	if (obj1)
-		got_object_close(obj1);
-	if (obj2)
-		got_object_close(obj2);
 	return error;
 }
 
@@ -2374,8 +2347,8 @@ blame_thread(void *arg)
 }
 
 static struct got_object_id *
-get_selected_commit_id(struct tog_blame_line *lines,
-    int first_displayed_line, int selected_line)
+get_selected_commit_id(struct tog_blame_line *lines, int first_displayed_line,
+    int selected_line)
 {
 	struct tog_blame_line *line;
 
@@ -2384,44 +2357,6 @@ get_selected_commit_id(struct tog_blame_line *lines,
 		return NULL;
 
 	return line->id;
-}
-
-static const struct got_error *
-open_selected_commit(struct got_object **pobj, struct got_object **obj,
-    struct tog_blame_line *lines, int first_displayed_line,
-    int selected_line, struct got_repository *repo)
-{
-	const struct got_error *err = NULL;
-	struct got_commit_object *commit = NULL;
-	struct got_object_id *selected_id;
-	struct got_object_qid *pid;
-
-	*pobj = NULL;
-	*obj = NULL;
-
-	selected_id = get_selected_commit_id(lines,
-	    first_displayed_line, selected_line);
-	if (selected_id == NULL)
-		return NULL;
-
-	err = got_object_open(obj, repo, selected_id);
-	if (err)
-		goto done;
-
-	err = got_object_commit_open(&commit, repo, *obj);
-	if (err)
-		goto done;
-
-	pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
-	if (pid) {
-		err = got_object_open(pobj, repo, pid->id);
-		if (err)
-			goto done;
-	}
-done:
-	if (commit)
-		got_object_commit_close(commit);
-	return err;
 }
 
 static const struct got_error *
@@ -2475,22 +2410,24 @@ run_blame(struct tog_blame *blame, struct tog_view *vi
 	struct got_blob_object *blob = NULL;
 	struct got_repository *thread_repo = NULL;
 	struct got_object_id *obj_id = NULL;
-	struct got_object *obj = NULL;
+	int obj_type;
 
 	err = got_object_id_by_path(&obj_id, repo, commit_id, path);
 	if (err)
-		goto done;
+		return err;
+	if (obj_id == NULL)
+		return got_error(GOT_ERR_NO_OBJ);
 
-	err = got_object_open(&obj, repo, obj_id);
+	err = got_object_get_type(&obj_type, repo, obj_id);
 	if (err)
 		goto done;
 
-	if (got_object_get_type(obj) != GOT_OBJ_TYPE_BLOB) {
+	if (obj_type != GOT_OBJ_TYPE_BLOB) {
 		err = got_error(GOT_ERR_OBJ_TYPE);
 		goto done;
 	}
 
-	err = got_object_blob_open(&blob, repo, obj, 8192);
+	err = got_object_open_as_blob(&blob, repo, obj_id, 8192);
 	if (err)
 		goto done;
 	blame->f = got_opentemp();
@@ -2533,8 +2470,6 @@ done:
 	if (blob)
 		got_object_blob_close(blob);
 	free(obj_id);
-	if (obj)
-		got_object_close(obj);
 	if (err)
 		stop_blame(blame);
 	return err;
@@ -2624,7 +2559,6 @@ input_blame_view(struct tog_view **new_view, struct to
     struct tog_view **focus_view, struct tog_view *view, int ch)
 {
 	const struct got_error *err = NULL, *thread_err = NULL;
-	struct got_object *obj = NULL, *pobj = NULL;
 	struct tog_view *diff_view;
 	struct tog_blame_view_state *s = &view->state.blame;
 	int begin_x = 0;
@@ -2664,36 +2598,60 @@ input_blame_view(struct tog_view **new_view, struct to
 			break;
 		case 'b':
 		case 'p': {
-			struct got_object_id *id;
+			struct got_object_id *id = NULL;
 			id = get_selected_commit_id(s->blame.lines,
 			    s->first_displayed_line, s->selected_line);
-			if (id == NULL || got_object_id_cmp(id,
-			    s->blamed_commit->id) == 0)
+			if (id == NULL)
 				break;
-			err = open_selected_commit(&pobj, &obj,
-			    s->blame.lines, s->first_displayed_line,
-			    s->selected_line, s->repo);
+			if (ch == 'p') {
+				struct got_commit_object *commit;
+				struct got_object_qid *pid;
+				struct got_object_id *blob_id = NULL;
+				int obj_type;
+				err = got_object_open_as_commit(&commit,
+				    s->repo, id);
+				if (err)
+					break;
+				pid = SIMPLEQ_FIRST(
+				    got_object_commit_get_parent_ids(commit));
+				if (pid == NULL) {
+					got_object_commit_close(commit);
+					break;
+				}
+				/* Check if path history ends here. */
+				err = got_object_id_by_path(&blob_id, s->repo,
+				    pid->id, s->path);
+				if (err) {
+					if (err->code == GOT_ERR_NO_TREE_ENTRY)
+						err = NULL;
+					got_object_commit_close(commit);
+					break;
+				}
+				err = got_object_get_type(&obj_type, s->repo,
+				    blob_id);
+				free(blob_id);
+				/* Can't blame non-blob type objects. */
+				if (obj_type != GOT_OBJ_TYPE_BLOB) {
+					got_object_commit_close(commit);
+					break;
+				}
+				err = got_object_qid_alloc(&s->blamed_commit,
+				    pid->id);
+				got_object_commit_close(commit);
+			} else {
+				if (got_object_id_cmp(id,
+				    s->blamed_commit->id) == 0)
+					break;
+				err = got_object_qid_alloc(&s->blamed_commit,
+				    id);
+			}
 			if (err)
 				break;
-			if (pobj == NULL && obj == NULL)
-				break;
-			if (ch == 'p' && pobj == NULL)
-				break;
 			s->done = 1;
 			thread_err = stop_blame(&s->blame);
 			s->done = 0;
 			if (thread_err)
 				break;
-			id = got_object_get_id(ch == 'b' ? obj : pobj);
-			got_object_close(obj);
-			obj = NULL;
-			if (pobj) {
-				got_object_close(pobj);
-				pobj = NULL;
-			}
-			err = got_object_qid_alloc(&s->blamed_commit, id);
-			if (err)
-				goto done;
 			SIMPLEQ_INSERT_HEAD(&s->blamed_commits,
 			    s->blamed_commit, entry);
 			err = run_blame(&s->blame, view, &s->blame_complete,
@@ -2727,23 +2685,31 @@ input_blame_view(struct tog_view **new_view, struct to
 			break;
 		}
 		case KEY_ENTER:
-		case '\r':
-			err = open_selected_commit(&pobj, &obj,
-			    s->blame.lines, s->first_displayed_line,
-			    s->selected_line, s->repo);
+		case '\r': {
+			struct got_object_id *id = NULL;
+			struct got_object_qid *pid;
+			struct got_commit_object *commit = NULL;
+			id = get_selected_commit_id(s->blame.lines,
+			    s->first_displayed_line, s->selected_line);
+			if (id == NULL || got_object_id_cmp(id,
+			    s->blamed_commit->id) == 0)
+				break;
+			err = got_object_open_as_commit(&commit, s->repo, id);
 			if (err)
 				break;
-			if (pobj == NULL && obj == NULL)
-				break;
-
+			pid = SIMPLEQ_FIRST(
+			    got_object_commit_get_parent_ids(commit));
 			if (view_is_parent_view(view))
 			    begin_x = view_split_begin_x(view->begin_x);
 			diff_view = view_open(0, 0, 0, begin_x, TOG_VIEW_DIFF);
 			if (diff_view == NULL) {
+				got_object_commit_close(commit);
 				err = got_error_from_errno();
 				break;
 			}
-			err = open_diff_view(diff_view, pobj, obj, s->repo);
+			err = open_diff_view(diff_view, pid ? pid->id : NULL,
+			    id, s->repo);
+			got_object_commit_close(commit);
 			if (err) {
 				view_close(diff_view);
 				break;
@@ -2751,7 +2717,7 @@ input_blame_view(struct tog_view **new_view, struct to
 			if (view_is_parent_view(view)) {
 				err = view_close_child(view);
 				if (err)
-					return err;
+					break;
 				err = view_set_child(view, diff_view);
 				if (err) {
 					view_close(diff_view);
@@ -2761,15 +2727,10 @@ input_blame_view(struct tog_view **new_view, struct to
 				view->child_focussed = 1;
 			} else
 				*new_view = diff_view;
-			if (pobj) {
-				got_object_close(pobj);
-				pobj = NULL;
-			}
-			got_object_close(obj);
-			obj = NULL;
 			if (err)
 				break;
 			break;
+		}
 		case KEY_NPAGE:
 		case ' ':
 			if (s->last_displayed_line >= s->blame.nlines &&
@@ -2796,9 +2757,6 @@ input_blame_view(struct tog_view **new_view, struct to
 		default:
 			break;
 	}
-done:
-	if (pobj)
-		got_object_close(pobj);
 	return thread_err ? thread_err : err;
 }
 
@@ -2873,14 +2831,8 @@ cmd_blame(int argc, char *argv[])
 		error = got_ref_resolve(&commit_id, repo, head_ref);
 		got_ref_close(head_ref);
 	} else {
-		struct got_object *obj;
-		error = got_object_open_by_id_str(&obj, repo, commit_id_str);
-		if (error != NULL)
-			goto done;
-		commit_id = got_object_id_dup(got_object_get_id(obj));
-		if (commit_id == NULL)
-			error = got_error_from_errno();
-		got_object_close(obj);
+		error = got_object_resolve_id_str(&commit_id, repo,
+		    commit_id_str);
 	}
 	if (error != NULL)
 		goto done;
@@ -3462,19 +3414,11 @@ cmd_tree(int argc, char *argv[])
 	if (error != NULL)
 		return error;
 
-	if (commit_id_arg == NULL) {
+	if (commit_id_arg == NULL)
 		error = get_head_commit_id(&commit_id, repo);
-		if (error != NULL)
-			goto done;
-	} else {
-		struct got_object *obj;
-		error = got_object_open_by_id_str(&obj, repo, commit_id_arg);
-		if (error == NULL) {
-			commit_id = got_object_id_dup(got_object_get_id(obj));
-			if (commit_id == NULL)
-				error = got_error_from_errno();
-		}
-	}
+	else
+		error = got_object_resolve_id_str(&commit_id, repo,
+		    commit_id_arg);
 	if (error != NULL)
 		goto done;