Merge branch 'bc/object-id'

The "unsigned char sha1[20]" to "struct object_id" conversion
continues.  Notable changes in this round includes that ce->sha1,
i.e. the object name recorded in the cache_entry, turns into an
object_id.

It had merge conflicts with a few topics in flight (Christian's
"apply.c split", Dscho's "cat-file --filters" and Jeff Hostetler's
"status --porcelain-v2").  Extra sets of eyes double-checking for
mismerges are highly appreciated.

* bc/object-id:
  builtin/reset: convert to use struct object_id
  builtin/commit-tree: convert to struct object_id
  builtin/am: convert to struct object_id
  refs: add an update_ref_oid function.
  sha1_name: convert get_sha1_mb to struct object_id
  builtin/update-index: convert file to struct object_id
  notes: convert init_notes to use struct object_id
  builtin/rm: convert to use struct object_id
  builtin/blame: convert file to use struct object_id
  Convert read_mmblob to take struct object_id.
  notes-merge: convert struct notes_merge_pair to struct object_id
  builtin/checkout: convert some static functions to struct object_id
  streaming: make stream_blob_to_fd take struct object_id
  builtin: convert textconv_object to use struct object_id
  builtin/cat-file: convert some static functions to struct object_id
  builtin/cat-file: convert struct expand_data to use struct object_id
  builtin/log: convert some static functions to use struct object_id
  builtin/blame: convert struct origin to use struct object_id
  builtin/apply: convert static functions to struct object_id
  cache: convert struct cache_entry to use struct object_id
diff --git a/apply.c b/apply.c
index 289cbd0..e327021 100644
--- a/apply.c
+++ b/apply.c
@@ -3131,7 +3131,7 @@ static int apply_binary(struct apply_state *state,
 			struct patch *patch)
 {
 	const char *name = patch->old_name ? patch->old_name : patch->new_name;
-	unsigned char sha1[20];
+	struct object_id oid;
 
 	/*
 	 * For safety, we require patch index line to contain
@@ -3139,8 +3139,8 @@ static int apply_binary(struct apply_state *state,
 	 */
 	if (strlen(patch->old_sha1_prefix) != 40 ||
 	    strlen(patch->new_sha1_prefix) != 40 ||
-	    get_sha1_hex(patch->old_sha1_prefix, sha1) ||
-	    get_sha1_hex(patch->new_sha1_prefix, sha1))
+	    get_oid_hex(patch->old_sha1_prefix, &oid) ||
+	    get_oid_hex(patch->new_sha1_prefix, &oid))
 		return error("cannot apply binary patch to '%s' "
 			     "without full index line", name);
 
@@ -3149,12 +3149,12 @@ static int apply_binary(struct apply_state *state,
 		 * See if the old one matches what the patch
 		 * applies to.
 		 */
-		hash_sha1_file(img->buf, img->len, blob_type, sha1);
-		if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
+		hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+		if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
 			return error("the patch applies to '%s' (%s), "
 				     "which does not match the "
 				     "current contents.",
-				     name, sha1_to_hex(sha1));
+				     name, oid_to_hex(&oid));
 	}
 	else {
 		/* Otherwise, the old one must be empty. */
@@ -3163,19 +3163,19 @@ static int apply_binary(struct apply_state *state,
 				     "'%s' but it is not empty", name);
 	}
 
-	get_sha1_hex(patch->new_sha1_prefix, sha1);
-	if (is_null_sha1(sha1)) {
+	get_oid_hex(patch->new_sha1_prefix, &oid);
+	if (is_null_oid(&oid)) {
 		clear_image(img);
 		return 0; /* deletion patch */
 	}
 
-	if (has_sha1_file(sha1)) {
+	if (has_sha1_file(oid.hash)) {
 		/* We already have the postimage */
 		enum object_type type;
 		unsigned long size;
 		char *result;
 
-		result = read_sha1_file(sha1, &type, &size);
+		result = read_sha1_file(oid.hash, &type, &size);
 		if (!result)
 			return error("the necessary postimage %s for "
 				     "'%s' cannot be read",
@@ -3194,10 +3194,10 @@ static int apply_binary(struct apply_state *state,
 				     name);
 
 		/* verify that the result matches */
-		hash_sha1_file(img->buf, img->len, blob_type, sha1);
-		if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
+		hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+		if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
 			return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
-				name, patch->new_sha1_prefix, sha1_to_hex(sha1));
+				name, patch->new_sha1_prefix, oid_to_hex(&oid));
 	}
 
 	return 0;
@@ -3227,17 +3227,17 @@ static int apply_fragments(struct apply_state *state, struct image *img, struct
 	return 0;
 }
 
-static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
+static int read_blob_object(struct strbuf *buf, const struct object_id *oid, unsigned mode)
 {
 	if (S_ISGITLINK(mode)) {
 		strbuf_grow(buf, 100);
-		strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
+		strbuf_addf(buf, "Subproject commit %s\n", oid_to_hex(oid));
 	} else {
 		enum object_type type;
 		unsigned long sz;
 		char *result;
 
-		result = read_sha1_file(sha1, &type, &sz);
+		result = read_sha1_file(oid->hash, &type, &sz);
 		if (!result)
 			return -1;
 		/* XXX read_sha1_file NUL-terminates */
@@ -3250,7 +3250,7 @@ static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf
 {
 	if (!ce)
 		return 0;
-	return read_blob_object(buf, ce->sha1, ce->ce_mode);
+	return read_blob_object(buf, &ce->oid, ce->ce_mode);
 }
 
 static struct patch *in_fn_table(struct apply_state *state, const char *name)
@@ -3457,9 +3457,9 @@ static int load_preimage(struct apply_state *state,
 
 static int three_way_merge(struct image *image,
 			   char *path,
-			   const unsigned char *base,
-			   const unsigned char *ours,
-			   const unsigned char *theirs)
+			   const struct object_id *base,
+			   const struct object_id *ours,
+			   const struct object_id *theirs)
 {
 	mmfile_t base_file, our_file, their_file;
 	mmbuffer_t result = { NULL };
@@ -3536,7 +3536,7 @@ static int try_threeway(struct apply_state *state,
 			struct stat *st,
 			const struct cache_entry *ce)
 {
-	unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
+	struct object_id pre_oid, post_oid, our_oid;
 	struct strbuf buf = STRBUF_INIT;
 	size_t len;
 	int status;
@@ -3550,9 +3550,9 @@ static int try_threeway(struct apply_state *state,
 
 	/* Preimage the patch was prepared for */
 	if (patch->is_new)
-		write_sha1_file("", 0, blob_type, pre_sha1);
-	else if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
-		 read_blob_object(&buf, pre_sha1, patch->old_mode))
+		write_sha1_file("", 0, blob_type, pre_oid.hash);
+	else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) ||
+		 read_blob_object(&buf, &pre_oid, patch->old_mode))
 		return error("repository lacks the necessary blob to fall back on 3-way merge.");
 
 	if (state->apply_verbosity > verbosity_silent)
@@ -3565,11 +3565,11 @@ static int try_threeway(struct apply_state *state,
 		clear_image(&tmp_image);
 		return -1;
 	}
-	/* post_sha1[] is theirs */
-	write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
+	/* post_oid is theirs */
+	write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
 	clear_image(&tmp_image);
 
-	/* our_sha1[] is ours */
+	/* our_oid is ours */
 	if (patch->is_new) {
 		if (load_current(state, &tmp_image, patch))
 			return error("cannot read the current contents of '%s'",
@@ -3579,12 +3579,12 @@ static int try_threeway(struct apply_state *state,
 			return error("cannot read the current contents of '%s'",
 				     patch->old_name);
 	}
-	write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
+	write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
 	clear_image(&tmp_image);
 
 	/* in-core three-way merge between post and our using pre as base */
 	status = three_way_merge(image, patch->new_name,
-				 pre_sha1, our_sha1, post_sha1);
+				 &pre_oid, &our_oid, &post_oid);
 	if (status < 0) {
 		if (state->apply_verbosity > verbosity_silent)
 			fprintf(stderr,
@@ -3597,9 +3597,9 @@ static int try_threeway(struct apply_state *state,
 		if (patch->is_new)
 			oidclr(&patch->threeway_stage[0]);
 		else
-			hashcpy(patch->threeway_stage[0].hash, pre_sha1);
-		hashcpy(patch->threeway_stage[1].hash, our_sha1);
-		hashcpy(patch->threeway_stage[2].hash, post_sha1);
+			oidcpy(&patch->threeway_stage[0], &pre_oid);
+		oidcpy(&patch->threeway_stage[1], &our_oid);
+		oidcpy(&patch->threeway_stage[2], &post_oid);
 		if (state->apply_verbosity > verbosity_silent)
 			fprintf(stderr,
 				"Applied patch to '%s' with conflicts.\n",
@@ -4001,9 +4001,9 @@ static int read_apply_cache(struct apply_state *state)
 		return read_cache();
 }
 
-/* This function tries to read the sha1 from the current index */
-static int get_current_sha1(struct apply_state *state, const char *path,
-			    unsigned char *sha1)
+/* This function tries to read the object name from the current index */
+static int get_current_oid(struct apply_state *state, const char *path,
+			   struct object_id *oid)
 {
 	int pos;
 
@@ -4012,11 +4012,11 @@ static int get_current_sha1(struct apply_state *state, const char *path,
 	pos = cache_name_pos(path, strlen(path));
 	if (pos < 0)
 		return -1;
-	hashcpy(sha1, active_cache[pos]->sha1);
+	oidcpy(oid, &active_cache[pos]->oid);
 	return 0;
 }
 
-static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20])
+static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
 {
 	/*
 	 * A usable gitlink patch has only one fragment (hunk) that looks like:
@@ -4040,14 +4040,14 @@ static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20
 	    (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
 	    starts_with(++preimage, heading) &&
 	    /* does it record full SHA-1? */
-	    !get_sha1_hex(preimage + sizeof(heading) - 1, sha1) &&
-	    preimage[sizeof(heading) + 40 - 1] == '\n' &&
+	    !get_oid_hex(preimage + sizeof(heading) - 1, oid) &&
+	    preimage[sizeof(heading) + GIT_SHA1_HEXSZ - 1] == '\n' &&
 	    /* does the abbreviated name on the index line agree with it? */
 	    starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
 		return 0; /* it all looks fine */
 
 	/* we may have full object name on the index line */
-	return get_sha1_hex(p->old_sha1_prefix, sha1);
+	return get_oid_hex(p->old_sha1_prefix, oid);
 }
 
 /* Build an index that contains the just the files needed for a 3way merge */
@@ -4062,7 +4062,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 	 * worth showing the new sha1 prefix, but until then...
 	 */
 	for (patch = list; patch; patch = patch->next) {
-		unsigned char sha1[20];
+		struct object_id oid;
 		struct cache_entry *ce;
 		const char *name;
 
@@ -4071,23 +4071,23 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 			continue;
 
 		if (S_ISGITLINK(patch->old_mode)) {
-			if (!preimage_sha1_in_gitlink_patch(patch, sha1))
+			if (!preimage_oid_in_gitlink_patch(patch, &oid))
 				; /* ok, the textual part looks sane */
 			else
 				return error("sha1 information is lacking or "
 					     "useless for submodule %s", name);
-		} else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
+		} else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) {
 			; /* ok */
 		} else if (!patch->lines_added && !patch->lines_deleted) {
 			/* mode-only change: update the current */
-			if (get_current_sha1(state, patch->old_name, sha1))
+			if (get_current_oid(state, patch->old_name, &oid))
 				return error("mode change for %s, which is not "
 					     "in current HEAD", name);
 		} else
 			return error("sha1 information is lacking or useless "
 				     "(%s).", name);
 
-		ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);
+		ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);
 		if (!ce)
 			return error(_("make_cache_entry failed for path '%s'"),
 				     name);
@@ -4102,179 +4102,179 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 	res = write_locked_index(&result, &lock, COMMIT_LOCK);
 	discard_index(&result);
 
-	if (res)
-		return error("Could not write temporary index to %s",
-			     state->fake_ancestor);
+	 if (res)
+		 return error("Could not write temporary index to %s",
+			      state->fake_ancestor);
 
-	return 0;
-}
+	 return 0;
+ }
 
-static void stat_patch_list(struct apply_state *state, struct patch *patch)
-{
-	int files, adds, dels;
+ static void stat_patch_list(struct apply_state *state, struct patch *patch)
+ {
+	 int files, adds, dels;
 
-	for (files = adds = dels = 0 ; patch ; patch = patch->next) {
-		files++;
-		adds += patch->lines_added;
-		dels += patch->lines_deleted;
-		show_stats(state, patch);
-	}
+	 for (files = adds = dels = 0 ; patch ; patch = patch->next) {
+		 files++;
+		 adds += patch->lines_added;
+		 dels += patch->lines_deleted;
+		 show_stats(state, patch);
+	 }
 
-	print_stat_summary(stdout, files, adds, dels);
-}
+	 print_stat_summary(stdout, files, adds, dels);
+ }
 
-static void numstat_patch_list(struct apply_state *state,
-			       struct patch *patch)
-{
-	for ( ; patch; patch = patch->next) {
-		const char *name;
-		name = patch->new_name ? patch->new_name : patch->old_name;
-		if (patch->is_binary)
-			printf("-\t-\t");
-		else
-			printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
-		write_name_quoted(name, stdout, state->line_termination);
-	}
-}
+ static void numstat_patch_list(struct apply_state *state,
+				struct patch *patch)
+ {
+	 for ( ; patch; patch = patch->next) {
+		 const char *name;
+		 name = patch->new_name ? patch->new_name : patch->old_name;
+		 if (patch->is_binary)
+			 printf("-\t-\t");
+		 else
+			 printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+		 write_name_quoted(name, stdout, state->line_termination);
+	 }
+ }
 
-static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
-{
-	if (mode)
-		printf(" %s mode %06o %s\n", newdelete, mode, name);
-	else
-		printf(" %s %s\n", newdelete, name);
-}
+ static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
+ {
+	 if (mode)
+		 printf(" %s mode %06o %s\n", newdelete, mode, name);
+	 else
+		 printf(" %s %s\n", newdelete, name);
+ }
 
-static void show_mode_change(struct patch *p, int show_name)
-{
-	if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
-		if (show_name)
-			printf(" mode change %06o => %06o %s\n",
-			       p->old_mode, p->new_mode, p->new_name);
-		else
-			printf(" mode change %06o => %06o\n",
-			       p->old_mode, p->new_mode);
-	}
-}
+ static void show_mode_change(struct patch *p, int show_name)
+ {
+	 if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
+		 if (show_name)
+			 printf(" mode change %06o => %06o %s\n",
+				p->old_mode, p->new_mode, p->new_name);
+		 else
+			 printf(" mode change %06o => %06o\n",
+				p->old_mode, p->new_mode);
+	 }
+ }
 
-static void show_rename_copy(struct patch *p)
-{
-	const char *renamecopy = p->is_rename ? "rename" : "copy";
-	const char *old, *new;
+ static void show_rename_copy(struct patch *p)
+ {
+	 const char *renamecopy = p->is_rename ? "rename" : "copy";
+	 const char *old, *new;
 
-	/* Find common prefix */
-	old = p->old_name;
-	new = p->new_name;
-	while (1) {
-		const char *slash_old, *slash_new;
-		slash_old = strchr(old, '/');
-		slash_new = strchr(new, '/');
-		if (!slash_old ||
-		    !slash_new ||
-		    slash_old - old != slash_new - new ||
-		    memcmp(old, new, slash_new - new))
-			break;
-		old = slash_old + 1;
-		new = slash_new + 1;
-	}
-	/* p->old_name thru old is the common prefix, and old and new
-	 * through the end of names are renames
-	 */
-	if (old != p->old_name)
-		printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
-		       (int)(old - p->old_name), p->old_name,
-		       old, new, p->score);
-	else
-		printf(" %s %s => %s (%d%%)\n", renamecopy,
-		       p->old_name, p->new_name, p->score);
-	show_mode_change(p, 0);
-}
+	 /* Find common prefix */
+	 old = p->old_name;
+	 new = p->new_name;
+	 while (1) {
+		 const char *slash_old, *slash_new;
+		 slash_old = strchr(old, '/');
+		 slash_new = strchr(new, '/');
+		 if (!slash_old ||
+		     !slash_new ||
+		     slash_old - old != slash_new - new ||
+		     memcmp(old, new, slash_new - new))
+			 break;
+		 old = slash_old + 1;
+		 new = slash_new + 1;
+	 }
+	 /* p->old_name thru old is the common prefix, and old and new
+	  * through the end of names are renames
+	  */
+	 if (old != p->old_name)
+		 printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
+			(int)(old - p->old_name), p->old_name,
+			old, new, p->score);
+	 else
+		 printf(" %s %s => %s (%d%%)\n", renamecopy,
+			p->old_name, p->new_name, p->score);
+	 show_mode_change(p, 0);
+ }
 
-static void summary_patch_list(struct patch *patch)
-{
-	struct patch *p;
+ static void summary_patch_list(struct patch *patch)
+ {
+	 struct patch *p;
 
-	for (p = patch; p; p = p->next) {
-		if (p->is_new)
-			show_file_mode_name("create", p->new_mode, p->new_name);
-		else if (p->is_delete)
-			show_file_mode_name("delete", p->old_mode, p->old_name);
-		else {
-			if (p->is_rename || p->is_copy)
-				show_rename_copy(p);
-			else {
-				if (p->score) {
-					printf(" rewrite %s (%d%%)\n",
-					       p->new_name, p->score);
-					show_mode_change(p, 0);
-				}
-				else
-					show_mode_change(p, 1);
-			}
-		}
-	}
-}
+	 for (p = patch; p; p = p->next) {
+		 if (p->is_new)
+			 show_file_mode_name("create", p->new_mode, p->new_name);
+		 else if (p->is_delete)
+			 show_file_mode_name("delete", p->old_mode, p->old_name);
+		 else {
+			 if (p->is_rename || p->is_copy)
+				 show_rename_copy(p);
+			 else {
+				 if (p->score) {
+					 printf(" rewrite %s (%d%%)\n",
+						p->new_name, p->score);
+					 show_mode_change(p, 0);
+				 }
+				 else
+					 show_mode_change(p, 1);
+			 }
+		 }
+	 }
+ }
 
-static void patch_stats(struct apply_state *state, struct patch *patch)
-{
-	int lines = patch->lines_added + patch->lines_deleted;
+ static void patch_stats(struct apply_state *state, struct patch *patch)
+ {
+	 int lines = patch->lines_added + patch->lines_deleted;
 
-	if (lines > state->max_change)
-		state->max_change = lines;
-	if (patch->old_name) {
-		int len = quote_c_style(patch->old_name, NULL, NULL, 0);
-		if (!len)
-			len = strlen(patch->old_name);
-		if (len > state->max_len)
-			state->max_len = len;
-	}
-	if (patch->new_name) {
-		int len = quote_c_style(patch->new_name, NULL, NULL, 0);
-		if (!len)
-			len = strlen(patch->new_name);
-		if (len > state->max_len)
-			state->max_len = len;
-	}
-}
+	 if (lines > state->max_change)
+		 state->max_change = lines;
+	 if (patch->old_name) {
+		 int len = quote_c_style(patch->old_name, NULL, NULL, 0);
+		 if (!len)
+			 len = strlen(patch->old_name);
+		 if (len > state->max_len)
+			 state->max_len = len;
+	 }
+	 if (patch->new_name) {
+		 int len = quote_c_style(patch->new_name, NULL, NULL, 0);
+		 if (!len)
+			 len = strlen(patch->new_name);
+		 if (len > state->max_len)
+			 state->max_len = len;
+	 }
+ }
 
-static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
-{
-	if (state->update_index) {
-		if (remove_file_from_cache(patch->old_name) < 0)
-			return error(_("unable to remove %s from index"), patch->old_name);
-	}
-	if (!state->cached) {
-		if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
-			remove_path(patch->old_name);
-		}
-	}
-	return 0;
-}
+ static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
+ {
+	 if (state->update_index) {
+		 if (remove_file_from_cache(patch->old_name) < 0)
+			 return error(_("unable to remove %s from index"), patch->old_name);
+	 }
+	 if (!state->cached) {
+		 if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
+			 remove_path(patch->old_name);
+		 }
+	 }
+	 return 0;
+ }
 
-static int add_index_file(struct apply_state *state,
-			  const char *path,
-			  unsigned mode,
-			  void *buf,
-			  unsigned long size)
-{
-	struct stat st;
-	struct cache_entry *ce;
-	int namelen = strlen(path);
-	unsigned ce_size = cache_entry_size(namelen);
+ static int add_index_file(struct apply_state *state,
+			   const char *path,
+			   unsigned mode,
+			   void *buf,
+			   unsigned long size)
+ {
+	 struct stat st;
+	 struct cache_entry *ce;
+	 int namelen = strlen(path);
+	 unsigned ce_size = cache_entry_size(namelen);
 
-	if (!state->update_index)
-		return 0;
+	 if (!state->update_index)
+		 return 0;
 
-	ce = xcalloc(1, ce_size);
-	memcpy(ce->name, path, namelen);
-	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(0);
-	ce->ce_namelen = namelen;
-	if (S_ISGITLINK(mode)) {
-		const char *s;
+	 ce = xcalloc(1, ce_size);
+	 memcpy(ce->name, path, namelen);
+	 ce->ce_mode = create_ce_mode(mode);
+	 ce->ce_flags = create_ce_flags(0);
+	 ce->ce_namelen = namelen;
+	 if (S_ISGITLINK(mode)) {
+		 const char *s;
 
-		if (!skip_prefix(buf, "Subproject commit ", &s) ||
-		    get_sha1_hex(s, ce->sha1)) {
+		 if (!skip_prefix(buf, "Subproject commit ", &s) ||
+		     get_oid_hex(s, &ce->oid)) {
 			free(ce);
 			return error(_("corrupt patch for submodule %s"), path);
 		}
@@ -4288,7 +4288,7 @@ static int add_index_file(struct apply_state *state,
 			}
 			fill_stat_cache_info(ce, &st);
 		}
-		if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0) {
+		if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
 			free(ce);
 			return error(_("unable to create backing store "
 				       "for newly created file %s"), path);
@@ -4437,7 +4437,7 @@ static int add_conflicted_stages_file(struct apply_state *state,
 		ce->ce_mode = create_ce_mode(mode);
 		ce->ce_flags = create_ce_flags(stage);
 		ce->ce_namelen = namelen;
-		hashcpy(ce->sha1, patch->threeway_stage[stage - 1].hash);
+		oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
 		if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
 			free(ce);
 			return error(_("unable to add cache entry for %s"),
diff --git a/builtin.h b/builtin.h
index 6b95006..b9122bc 100644
--- a/builtin.h
+++ b/builtin.h
@@ -25,7 +25,7 @@ struct fmt_merge_msg_opts {
 extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 			 struct fmt_merge_msg_opts *);
 
-extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const struct object_id *oid, int oid_valid, char **buf, unsigned long *buf_size);
 
 extern int is_builtin(const char *s);
 
diff --git a/builtin/am.c b/builtin/am.c
index ddd23ba..6981f42 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -110,7 +110,7 @@ struct am_state {
 	size_t msg_len;
 
 	/* when --rebasing, records the original commit the patch came from */
-	unsigned char orig_commit[GIT_SHA1_RAWSZ];
+	struct object_id orig_commit;
 
 	/* number of digits in patch filename */
 	int prec;
@@ -416,8 +416,8 @@ static void am_load(struct am_state *state)
 	read_commit_msg(state);
 
 	if (read_state_file(&sb, state, "original-commit", 1) < 0)
-		hashclr(state->orig_commit);
-	else if (get_sha1_hex(sb.buf, state->orig_commit) < 0)
+		oidclr(&state->orig_commit);
+	else if (get_oid_hex(sb.buf, &state->orig_commit) < 0)
 		die(_("could not parse %s"), am_path(state, "original-commit"));
 
 	read_state_file(&sb, state, "threeway", 1);
@@ -543,14 +543,14 @@ static int copy_notes_for_rebase(const struct am_state *state)
 	fp = xfopen(am_path(state, "rewritten"), "r");
 
 	while (!strbuf_getline_lf(&sb, fp)) {
-		unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];
+		struct object_id from_obj, to_obj;
 
 		if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {
 			ret = error(invalid_line, sb.buf);
 			goto finish;
 		}
 
-		if (get_sha1_hex(sb.buf, from_obj)) {
+		if (get_oid_hex(sb.buf, &from_obj)) {
 			ret = error(invalid_line, sb.buf);
 			goto finish;
 		}
@@ -560,14 +560,14 @@ static int copy_notes_for_rebase(const struct am_state *state)
 			goto finish;
 		}
 
-		if (get_sha1_hex(sb.buf + GIT_SHA1_HEXSZ + 1, to_obj)) {
+		if (get_oid_hex(sb.buf + GIT_SHA1_HEXSZ + 1, &to_obj)) {
 			ret = error(invalid_line, sb.buf);
 			goto finish;
 		}
 
-		if (copy_note_for_rewrite(c, from_obj, to_obj))
+		if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash))
 			ret = error(_("Failed to copy notes from '%s' to '%s'"),
-					sha1_to_hex(from_obj), sha1_to_hex(to_obj));
+					oid_to_hex(&from_obj), oid_to_hex(&to_obj));
 	}
 
 finish:
@@ -973,7 +973,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
 static void am_setup(struct am_state *state, enum patch_format patch_format,
 			const char **paths, int keep_cr)
 {
-	unsigned char curr_head[GIT_SHA1_RAWSZ];
+	struct object_id curr_head;
 	const char *str;
 	struct strbuf sb = STRBUF_INIT;
 
@@ -1041,10 +1041,10 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
 	else
 		write_state_text(state, "applying", "");
 
-	if (!get_sha1("HEAD", curr_head)) {
-		write_state_text(state, "abort-safety", sha1_to_hex(curr_head));
+	if (!get_oid("HEAD", &curr_head)) {
+		write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
 		if (!state->rebasing)
-			update_ref("am", "ORIG_HEAD", curr_head, NULL, 0,
+			update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
 					UPDATE_REFS_DIE_ON_ERR);
 	} else {
 		write_state_text(state, "abort-safety", "");
@@ -1069,7 +1069,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
  */
 static void am_next(struct am_state *state)
 {
-	unsigned char head[GIT_SHA1_RAWSZ];
+	struct object_id head;
 
 	free(state->author_name);
 	state->author_name = NULL;
@@ -1087,11 +1087,11 @@ static void am_next(struct am_state *state)
 	unlink(am_path(state, "author-script"));
 	unlink(am_path(state, "final-commit"));
 
-	hashclr(state->orig_commit);
+	oidclr(&state->orig_commit);
 	unlink(am_path(state, "original-commit"));
 
-	if (!get_sha1("HEAD", head))
-		write_state_text(state, "abort-safety", sha1_to_hex(head));
+	if (!get_oid("HEAD", &head))
+		write_state_text(state, "abort-safety", oid_to_hex(&head));
 	else
 		write_state_text(state, "abort-safety", "");
 
@@ -1133,17 +1133,17 @@ static void refresh_and_write_cache(void)
  */
 static int index_has_changes(struct strbuf *sb)
 {
-	unsigned char head[GIT_SHA1_RAWSZ];
+	struct object_id head;
 	int i;
 
-	if (!get_sha1_tree("HEAD", head)) {
+	if (!get_sha1_tree("HEAD", head.hash)) {
 		struct diff_options opt;
 
 		diff_setup(&opt);
 		DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
 		if (!sb)
 			DIFF_OPT_SET(&opt, QUICK);
-		do_diff_cache(head, &opt);
+		do_diff_cache(head.hash, &opt);
 		diffcore_std(&opt);
 		for (i = 0; sb && i < diff_queued_diff.nr; i++) {
 			if (i)
@@ -1350,7 +1350,7 @@ static int parse_mail(struct am_state *state, const char *mail)
  * Sets commit_id to the commit hash where the mail was generated from.
  * Returns 0 on success, -1 on failure.
  */
-static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
+static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
 {
 	struct strbuf sb = STRBUF_INIT;
 	FILE *fp = xfopen(mail, "r");
@@ -1362,7 +1362,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
 	if (!skip_prefix(sb.buf, "From ", &x))
 		return -1;
 
-	if (get_sha1_hex(x, commit_id) < 0)
+	if (get_oid_hex(x, commit_id) < 0)
 		return -1;
 
 	strbuf_release(&sb);
@@ -1452,12 +1452,12 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
 static void write_index_patch(const struct am_state *state)
 {
 	struct tree *tree;
-	unsigned char head[GIT_SHA1_RAWSZ];
+	struct object_id head;
 	struct rev_info rev_info;
 	FILE *fp;
 
-	if (!get_sha1_tree("HEAD", head))
-		tree = lookup_tree(head);
+	if (!get_sha1_tree("HEAD", head.hash))
+		tree = lookup_tree(head.hash);
 	else
 		tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
 
@@ -1487,19 +1487,19 @@ static void write_index_patch(const struct am_state *state)
 static int parse_mail_rebase(struct am_state *state, const char *mail)
 {
 	struct commit *commit;
-	unsigned char commit_sha1[GIT_SHA1_RAWSZ];
+	struct object_id commit_oid;
 
-	if (get_mail_commit_sha1(commit_sha1, mail) < 0)
+	if (get_mail_commit_oid(&commit_oid, mail) < 0)
 		die(_("could not parse %s"), mail);
 
-	commit = lookup_commit_or_die(commit_sha1, mail);
+	commit = lookup_commit_or_die(commit_oid.hash, mail);
 
 	get_commit_info(state, commit);
 
 	write_commit_patch(state, commit);
 
-	hashcpy(state->orig_commit, commit_sha1);
-	write_state_text(state, "original-commit", sha1_to_hex(commit_sha1));
+	oidcpy(&state->orig_commit, &commit_oid);
+	write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
 
 	return 0;
 }
@@ -1673,9 +1673,8 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
  */
 static void do_commit(const struct am_state *state)
 {
-	unsigned char tree[GIT_SHA1_RAWSZ], parent[GIT_SHA1_RAWSZ],
-		      commit[GIT_SHA1_RAWSZ];
-	unsigned char *ptr;
+	struct object_id tree, parent, commit;
+	const struct object_id *old_oid;
 	struct commit_list *parents = NULL;
 	const char *reflog_msg, *author;
 	struct strbuf sb = STRBUF_INIT;
@@ -1683,14 +1682,14 @@ static void do_commit(const struct am_state *state)
 	if (run_hook_le(NULL, "pre-applypatch", NULL))
 		exit(1);
 
-	if (write_cache_as_tree(tree, 0, NULL))
+	if (write_cache_as_tree(tree.hash, 0, NULL))
 		die(_("git write-tree failed to write a tree"));
 
-	if (!get_sha1_commit("HEAD", parent)) {
-		ptr = parent;
-		commit_list_insert(lookup_commit(parent), &parents);
+	if (!get_sha1_commit("HEAD", parent.hash)) {
+		old_oid = &parent;
+		commit_list_insert(lookup_commit(parent.hash), &parents);
 	} else {
-		ptr = NULL;
+		old_oid = NULL;
 		say(state, stderr, _("applying to an empty history"));
 	}
 
@@ -1702,7 +1701,7 @@ static void do_commit(const struct am_state *state)
 		setenv("GIT_COMMITTER_DATE",
 			state->ignore_date ? "" : state->author_date, 1);
 
-	if (commit_tree(state->msg, state->msg_len, tree, parents, commit,
+	if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
 				author, state->sign_commit))
 		die(_("failed to write commit object"));
 
@@ -1713,14 +1712,15 @@ static void do_commit(const struct am_state *state)
 	strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
 			state->msg);
 
-	update_ref(sb.buf, "HEAD", commit, ptr, 0, UPDATE_REFS_DIE_ON_ERR);
+	update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
+			UPDATE_REFS_DIE_ON_ERR);
 
 	if (state->rebasing) {
 		FILE *fp = xfopen(am_path(state, "rewritten"), "a");
 
-		assert(!is_null_sha1(state->orig_commit));
-		fprintf(fp, "%s ", sha1_to_hex(state->orig_commit));
-		fprintf(fp, "%s\n", sha1_to_hex(commit));
+		assert(!is_null_oid(&state->orig_commit));
+		fprintf(fp, "%s ", oid_to_hex(&state->orig_commit));
+		fprintf(fp, "%s\n", oid_to_hex(&commit));
 		fclose(fp);
 	}
 
@@ -2041,30 +2041,30 @@ static int merge_tree(struct tree *tree)
  * Clean the index without touching entries that are not modified between
  * `head` and `remote`.
  */
-static int clean_index(const unsigned char *head, const unsigned char *remote)
+static int clean_index(const struct object_id *head, const struct object_id *remote)
 {
 	struct tree *head_tree, *remote_tree, *index_tree;
-	unsigned char index[GIT_SHA1_RAWSZ];
+	struct object_id index;
 
-	head_tree = parse_tree_indirect(head);
+	head_tree = parse_tree_indirect(head->hash);
 	if (!head_tree)
-		return error(_("Could not parse object '%s'."), sha1_to_hex(head));
+		return error(_("Could not parse object '%s'."), oid_to_hex(head));
 
-	remote_tree = parse_tree_indirect(remote);
+	remote_tree = parse_tree_indirect(remote->hash);
 	if (!remote_tree)
-		return error(_("Could not parse object '%s'."), sha1_to_hex(remote));
+		return error(_("Could not parse object '%s'."), oid_to_hex(remote));
 
 	read_cache_unmerged();
 
 	if (fast_forward_to(head_tree, head_tree, 1))
 		return -1;
 
-	if (write_cache_as_tree(index, 0, NULL))
+	if (write_cache_as_tree(index.hash, 0, NULL))
 		return -1;
 
-	index_tree = parse_tree_indirect(index);
+	index_tree = parse_tree_indirect(index.hash);
 	if (!index_tree)
-		return error(_("Could not parse object '%s'."), sha1_to_hex(index));
+		return error(_("Could not parse object '%s'."), oid_to_hex(&index));
 
 	if (fast_forward_to(index_tree, remote_tree, 0))
 		return -1;
@@ -2092,14 +2092,14 @@ static void am_rerere_clear(void)
  */
 static void am_skip(struct am_state *state)
 {
-	unsigned char head[GIT_SHA1_RAWSZ];
+	struct object_id head;
 
 	am_rerere_clear();
 
-	if (get_sha1("HEAD", head))
-		hashcpy(head, EMPTY_TREE_SHA1_BIN);
+	if (get_oid("HEAD", &head))
+		hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);
 
-	if (clean_index(head, head))
+	if (clean_index(&head, &head))
 		die(_("failed to clean index"));
 
 	am_next(state);
@@ -2117,21 +2117,21 @@ static void am_skip(struct am_state *state)
 static int safe_to_abort(const struct am_state *state)
 {
 	struct strbuf sb = STRBUF_INIT;
-	unsigned char abort_safety[GIT_SHA1_RAWSZ], head[GIT_SHA1_RAWSZ];
+	struct object_id abort_safety, head;
 
 	if (file_exists(am_path(state, "dirtyindex")))
 		return 0;
 
 	if (read_state_file(&sb, state, "abort-safety", 1) > 0) {
-		if (get_sha1_hex(sb.buf, abort_safety))
+		if (get_oid_hex(sb.buf, &abort_safety))
 			die(_("could not parse %s"), am_path(state, "abort_safety"));
 	} else
-		hashclr(abort_safety);
+		oidclr(&abort_safety);
 
-	if (get_sha1("HEAD", head))
-		hashclr(head);
+	if (get_oid("HEAD", &head))
+		oidclr(&head);
 
-	if (!hashcmp(head, abort_safety))
+	if (!oidcmp(&head, &abort_safety))
 		return 1;
 
 	error(_("You seem to have moved HEAD since the last 'am' failure.\n"
@@ -2145,7 +2145,7 @@ static int safe_to_abort(const struct am_state *state)
  */
 static void am_abort(struct am_state *state)
 {
-	unsigned char curr_head[GIT_SHA1_RAWSZ], orig_head[GIT_SHA1_RAWSZ];
+	struct object_id curr_head, orig_head;
 	int has_curr_head, has_orig_head;
 	char *curr_branch;
 
@@ -2156,20 +2156,20 @@ static void am_abort(struct am_state *state)
 
 	am_rerere_clear();
 
-	curr_branch = resolve_refdup("HEAD", 0, curr_head, NULL);
-	has_curr_head = !is_null_sha1(curr_head);
+	curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+	has_curr_head = !is_null_oid(&curr_head);
 	if (!has_curr_head)
-		hashcpy(curr_head, EMPTY_TREE_SHA1_BIN);
+		hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
 
-	has_orig_head = !get_sha1("ORIG_HEAD", orig_head);
+	has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
 	if (!has_orig_head)
-		hashcpy(orig_head, EMPTY_TREE_SHA1_BIN);
+		hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);
 
-	clean_index(curr_head, orig_head);
+	clean_index(&curr_head, &orig_head);
 
 	if (has_orig_head)
-		update_ref("am --abort", "HEAD", orig_head,
-				has_curr_head ? curr_head : NULL, 0,
+		update_ref_oid("am --abort", "HEAD", &orig_head,
+				has_curr_head ? &curr_head : NULL, 0,
 				UPDATE_REFS_DIE_ON_ERR);
 	else if (curr_branch)
 		delete_ref(curr_branch, NULL, REF_NODEREF);
diff --git a/builtin/blame.c b/builtin/blame.c
index a5bbf91..ccaf8be 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -120,7 +120,7 @@ struct origin {
 	 */
 	struct blame_entry *suspects;
 	mmfile_t file;
-	unsigned char blob_sha1[20];
+	struct object_id blob_oid;
 	unsigned mode;
 	/* guilty gets set when shipping any suspects to the final
 	 * blame list instead of other commits
@@ -154,8 +154,8 @@ static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
  */
 int textconv_object(const char *path,
 		    unsigned mode,
-		    const unsigned char *sha1,
-		    int sha1_valid,
+		    const struct object_id *oid,
+		    int oid_valid,
 		    char **buf,
 		    unsigned long *buf_size)
 {
@@ -163,7 +163,7 @@ int textconv_object(const char *path,
 	struct userdiff_driver *textconv;
 
 	df = alloc_filespec(path);
-	fill_filespec(df, sha1, sha1_valid, mode);
+	fill_filespec(df, oid->hash, oid_valid, mode);
 	textconv = get_textconv(df);
 	if (!textconv) {
 		free_filespec(df);
@@ -188,15 +188,16 @@ static void fill_origin_blob(struct diff_options *opt,
 
 		num_read_blob++;
 		if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-		    textconv_object(o->path, o->mode, o->blob_sha1, 1, &file->ptr, &file_size))
+		    textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
 			;
 		else
-			file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
+			file->ptr = read_sha1_file(o->blob_oid.hash, &type,
+						   &file_size);
 		file->size = file_size;
 
 		if (!file->ptr)
 			die("Cannot read blob %s for path %s",
-			    sha1_to_hex(o->blob_sha1),
+			    oid_to_hex(&o->blob_oid),
 			    o->path);
 		o->file = *file;
 	}
@@ -508,17 +509,17 @@ static struct origin *get_origin(struct scoreboard *sb,
  */
 static int fill_blob_sha1_and_mode(struct origin *origin)
 {
-	if (!is_null_sha1(origin->blob_sha1))
+	if (!is_null_oid(&origin->blob_oid))
 		return 0;
 	if (get_tree_entry(origin->commit->object.oid.hash,
 			   origin->path,
-			   origin->blob_sha1, &origin->mode))
+			   origin->blob_oid.hash, &origin->mode))
 		goto error_out;
-	if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
+	if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
 		goto error_out;
 	return 0;
  error_out:
-	hashclr(origin->blob_sha1);
+	oidclr(&origin->blob_oid);
 	origin->mode = S_IFINVALID;
 	return -1;
 }
@@ -572,7 +573,7 @@ static struct origin *find_origin(struct scoreboard *sb,
 	if (!diff_queued_diff.nr) {
 		/* The path is the same as parent */
 		porigin = get_origin(sb, parent, origin->path);
-		hashcpy(porigin->blob_sha1, origin->blob_sha1);
+		oidcpy(&porigin->blob_oid, &origin->blob_oid);
 		porigin->mode = origin->mode;
 	} else {
 		/*
@@ -598,7 +599,7 @@ static struct origin *find_origin(struct scoreboard *sb,
 			    p->status);
 		case 'M':
 			porigin = get_origin(sb, parent, origin->path);
-			hashcpy(porigin->blob_sha1, p->one->oid.hash);
+			oidcpy(&porigin->blob_oid, &p->one->oid);
 			porigin->mode = p->one->mode;
 			break;
 		case 'A':
@@ -644,7 +645,7 @@ static struct origin *find_rename(struct scoreboard *sb,
 		if ((p->status == 'R' || p->status == 'C') &&
 		    !strcmp(p->two->path, origin->path)) {
 			porigin = get_origin(sb, parent, p->one->path);
-			hashcpy(porigin->blob_sha1, p->one->oid.hash);
+			oidcpy(&porigin->blob_oid, &p->one->oid);
 			porigin->mode = p->one->mode;
 			break;
 		}
@@ -1308,7 +1309,7 @@ static void find_copy_in_parent(struct scoreboard *sb,
 				continue;
 
 			norigin = get_origin(sb, parent, p->one->path);
-			hashcpy(norigin->blob_sha1, p->one->oid.hash);
+			oidcpy(&norigin->blob_oid, &p->one->oid);
 			norigin->mode = p->one->mode;
 			fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
 			if (!file_p.ptr)
@@ -1458,15 +1459,14 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
 			porigin = find(sb, p, origin);
 			if (!porigin)
 				continue;
-			if (!hashcmp(porigin->blob_sha1, origin->blob_sha1)) {
+			if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) {
 				pass_whole_blame(sb, origin, porigin);
 				origin_decref(porigin);
 				goto finish;
 			}
 			for (j = same = 0; j < i; j++)
 				if (sg_origin[j] &&
-				    !hashcmp(sg_origin[j]->blob_sha1,
-					     porigin->blob_sha1)) {
+				    !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) {
 					same = 1;
 					break;
 				}
@@ -1941,7 +1941,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
 	cp = nth_line(sb, ent->lno);
 	for (cnt = 0; cnt < ent->num_lines; cnt++) {
 		char ch;
-		int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : abbrev;
+		int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
 
 		if (suspect->commit->object.flags & UNINTERESTING) {
 			if (blank_boundary)
@@ -2232,12 +2232,12 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
 	int pos;
 
 	for (parents = work_tree->parents; parents; parents = parents->next) {
-		const unsigned char *commit_sha1 = parents->item->object.oid.hash;
-		unsigned char blob_sha1[20];
+		const struct object_id *commit_oid = &parents->item->object.oid;
+		struct object_id blob_oid;
 		unsigned mode;
 
-		if (!get_tree_entry(commit_sha1, path, blob_sha1, &mode) &&
-		    sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
+		if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
+		    sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
 			return;
 	}
 
@@ -2251,13 +2251,13 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
 		die("no such path '%s' in HEAD", path);
 }
 
-static struct commit_list **append_parent(struct commit_list **tail, const unsigned char *sha1)
+static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid)
 {
 	struct commit *parent;
 
-	parent = lookup_commit_reference(sha1);
+	parent = lookup_commit_reference(oid->hash);
 	if (!parent)
-		die("no such commit %s", sha1_to_hex(sha1));
+		die("no such commit %s", oid_to_hex(oid));
 	return &commit_list_insert(parent, tail)->next;
 }
 
@@ -2274,10 +2274,10 @@ static void append_merge_parents(struct commit_list **tail)
 	}
 
 	while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
-		unsigned char sha1[20];
-		if (line.len < 40 || get_sha1_hex(line.buf, sha1))
+		struct object_id oid;
+		if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
 			die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
-		tail = append_parent(tail, sha1);
+		tail = append_parent(tail, &oid);
 	}
 	close(merge_head);
 	strbuf_release(&line);
@@ -2306,7 +2306,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 	struct commit *commit;
 	struct origin *origin;
 	struct commit_list **parent_tail, *parent;
-	unsigned char head_sha1[20];
+	struct object_id head_oid;
 	struct strbuf buf = STRBUF_INIT;
 	const char *ident;
 	time_t now;
@@ -2322,10 +2322,10 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 	commit->date = now;
 	parent_tail = &commit->parents;
 
-	if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
+	if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
 		die("no such ref: HEAD");
 
-	parent_tail = append_parent(parent_tail, head_sha1);
+	parent_tail = append_parent(parent_tail, &head_oid);
 	append_merge_parents(parent_tail);
 	verify_working_tree_path(commit, path);
 
@@ -2366,7 +2366,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 		switch (st.st_mode & S_IFMT) {
 		case S_IFREG:
 			if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-			    textconv_object(read_from, mode, null_sha1, 0, &buf_ptr, &buf_len))
+			    textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
 				strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
 			else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
 				die_errno("cannot open or read '%s'", read_from);
@@ -2388,7 +2388,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 	convert_to_git(path, buf.buf, buf.len, &buf, 0);
 	origin->file.ptr = buf.buf;
 	origin->file.size = buf.len;
-	pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
+	pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
 
 	/*
 	 * Read the current index, replace the path entry with
@@ -2410,7 +2410,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 	}
 	size = cache_entry_size(len);
 	ce = xcalloc(1, size);
-	hashcpy(ce->sha1, origin->blob_sha1);
+	oidcpy(&ce->oid, &origin->blob_oid);
 	memcpy(ce->name, path, len);
 	ce->ce_flags = create_ce_flags(0);
 	ce->ce_namelen = len;
@@ -2793,16 +2793,16 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 			die("no such path %s in %s", path, final_commit_name);
 
 		if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
-		    textconv_object(path, o->mode, o->blob_sha1, 1, (char **) &sb.final_buf,
+		    textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb.final_buf,
 				    &sb.final_buf_size))
 			;
 		else
-			sb.final_buf = read_sha1_file(o->blob_sha1, &type,
+			sb.final_buf = read_sha1_file(o->blob_oid.hash, &type,
 						      &sb.final_buf_size);
 
 		if (!sb.final_buf)
 			die("Cannot read blob %s for path %s",
-			    sha1_to_hex(o->blob_sha1),
+			    oid_to_hex(&o->blob_oid),
 			    path);
 	}
 	num_read_blob++;
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 560f6c2..3ee9bc9 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -23,7 +23,7 @@ struct batch_options {
 static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 			int unknown_type)
 {
-	unsigned char sha1[20];
+	struct object_id oid;
 	enum object_type type;
 	char *buf;
 	unsigned long size;
@@ -35,14 +35,14 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 	if (unknown_type)
 		flags |= LOOKUP_UNKNOWN_OBJECT;
 
-	if (get_sha1_with_context(obj_name, 0, sha1, &obj_context))
+	if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context))
 		die("Not a valid object name %s", obj_name);
 
 	buf = NULL;
 	switch (opt) {
 	case 't':
 		oi.typename = &sb;
-		if (sha1_object_info_extended(sha1, &oi, flags) < 0)
+		if (sha1_object_info_extended(oid.hash, &oi, flags) < 0)
 			die("git cat-file: could not get object info");
 		if (sb.len) {
 			printf("%s\n", sb.buf);
@@ -53,24 +53,24 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 
 	case 's':
 		oi.sizep = &size;
-		if (sha1_object_info_extended(sha1, &oi, flags) < 0)
+		if (sha1_object_info_extended(oid.hash, &oi, flags) < 0)
 			die("git cat-file: could not get object info");
 		printf("%lu\n", size);
 		return 0;
 
 	case 'e':
-		return !has_sha1_file(sha1);
+		return !has_object_file(&oid);
 
 	case 'c':
 		if (!obj_context.path[0])
 			die("git cat-file --textconv %s: <object> must be <sha1:path>",
 			    obj_name);
 
-		if (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
+		if (textconv_object(obj_context.path, obj_context.mode, &oid, 1, &buf, &size))
 			break;
 
 	case 'p':
-		type = sha1_object_info(sha1, NULL);
+		type = sha1_object_info(oid.hash, NULL);
 		if (type < 0)
 			die("Not a valid object name %s", obj_name);
 
@@ -83,8 +83,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 		}
 
 		if (type == OBJ_BLOB)
-			return stream_blob_to_fd(1, sha1, NULL, 0);
-		buf = read_sha1_file(sha1, &type, &size);
+			return stream_blob_to_fd(1, &oid, NULL, 0);
+		buf = read_sha1_file(oid.hash, &type, &size);
 		if (!buf)
 			die("Cannot read object %s", obj_name);
 
@@ -93,19 +93,19 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 
 	case 0:
 		if (type_from_string(exp_type) == OBJ_BLOB) {
-			unsigned char blob_sha1[20];
-			if (sha1_object_info(sha1, NULL) == OBJ_TAG) {
-				char *buffer = read_sha1_file(sha1, &type, &size);
+			struct object_id blob_oid;
+			if (sha1_object_info(oid.hash, NULL) == OBJ_TAG) {
+				char *buffer = read_sha1_file(oid.hash, &type, &size);
 				const char *target;
 				if (!skip_prefix(buffer, "object ", &target) ||
-				    get_sha1_hex(target, blob_sha1))
-					die("%s not a valid tag", sha1_to_hex(sha1));
+				    get_oid_hex(target, &blob_oid))
+					die("%s not a valid tag", oid_to_hex(&oid));
 				free(buffer);
 			} else
-				hashcpy(blob_sha1, sha1);
+				oidcpy(&blob_oid, &oid);
 
-			if (sha1_object_info(blob_sha1, NULL) == OBJ_BLOB)
-				return stream_blob_to_fd(1, blob_sha1, NULL, 0);
+			if (sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
+				return stream_blob_to_fd(1, &blob_oid, NULL, 0);
 			/*
 			 * we attempted to dereference a tag to a blob
 			 * and failed; there may be new dereference
@@ -113,7 +113,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 			 * fall-back to the usual case.
 			 */
 		}
-		buf = read_object_with_reference(sha1, exp_type, &size, NULL);
+		buf = read_object_with_reference(oid.hash, exp_type, &size, NULL);
 		break;
 
 	default:
@@ -128,12 +128,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 }
 
 struct expand_data {
-	unsigned char sha1[20];
+	struct object_id oid;
 	enum object_type type;
 	unsigned long size;
 	off_t disk_size;
 	const char *rest;
-	unsigned char delta_base_sha1[20];
+	struct object_id delta_base_oid;
 
 	/*
 	 * If mark_query is true, we do not expand anything, but rather
@@ -176,7 +176,7 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
 
 	if (is_atom("objectname", atom, len)) {
 		if (!data->mark_query)
-			strbuf_addstr(sb, sha1_to_hex(data->sha1));
+			strbuf_addstr(sb, oid_to_hex(&data->oid));
 	} else if (is_atom("objecttype", atom, len)) {
 		if (data->mark_query)
 			data->info.typep = &data->type;
@@ -199,9 +199,10 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
 			strbuf_addstr(sb, data->rest);
 	} else if (is_atom("deltabase", atom, len)) {
 		if (data->mark_query)
-			data->info.delta_base_sha1 = data->delta_base_sha1;
+			data->info.delta_base_sha1 = data->delta_base_oid.hash;
 		else
-			strbuf_addstr(sb, sha1_to_hex(data->delta_base_sha1));
+			strbuf_addstr(sb,
+				      oid_to_hex(&data->delta_base_oid));
 	} else
 		die("unknown format element: %.*s", len, atom);
 }
@@ -232,28 +233,28 @@ static void batch_write(struct batch_options *opt, const void *data, int len)
 
 static void print_object_or_die(struct batch_options *opt, struct expand_data *data)
 {
-	const unsigned char *sha1 = data->sha1;
+	const struct object_id *oid = &data->oid;
 
 	assert(data->info.typep);
 
 	if (data->type == OBJ_BLOB) {
 		if (opt->buffer_output)
 			fflush(stdout);
-		if (stream_blob_to_fd(1, sha1, NULL, 0) < 0)
-			die("unable to stream %s to stdout", sha1_to_hex(sha1));
+		if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
+			die("unable to stream %s to stdout", oid_to_hex(oid));
 	}
 	else {
 		enum object_type type;
 		unsigned long size;
 		void *contents;
 
-		contents = read_sha1_file(sha1, &type, &size);
+		contents = read_sha1_file(oid->hash, &type, &size);
 		if (!contents)
-			die("object %s disappeared", sha1_to_hex(sha1));
+			die("object %s disappeared", oid_to_hex(oid));
 		if (type != data->type)
-			die("object %s changed type!?", sha1_to_hex(sha1));
+			die("object %s changed type!?", oid_to_hex(oid));
 		if (data->info.sizep && size != data->size)
-			die("object %s changed size!?", sha1_to_hex(sha1));
+			die("object %s changed size!?", oid_to_hex(oid));
 
 		batch_write(opt, contents, size);
 		free(contents);
@@ -266,8 +267,9 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
 	struct strbuf buf = STRBUF_INIT;
 
 	if (!data->skip_object_info &&
-	    sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
-		printf("%s missing\n", obj_name ? obj_name : sha1_to_hex(data->sha1));
+	    sha1_object_info_extended(data->oid.hash, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
+		printf("%s missing\n",
+		       obj_name ? obj_name : oid_to_hex(&data->oid));
 		fflush(stdout);
 		return;
 	}
@@ -290,7 +292,7 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
 	int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0;
 	enum follow_symlinks_result result;
 
-	result = get_sha1_with_context(obj_name, flags, data->sha1, &ctx);
+	result = get_sha1_with_context(obj_name, flags, data->oid.hash, &ctx);
 	if (result != FOUND) {
 		switch (result) {
 		case MISSING_OBJECT:
@@ -336,7 +338,7 @@ struct object_cb_data {
 static void batch_object_cb(const unsigned char sha1[20], void *vdata)
 {
 	struct object_cb_data *data = vdata;
-	hashcpy(data->expand->sha1, sha1);
+	hashcpy(data->expand->oid.hash, sha1);
 	batch_object_write(NULL, data->opt, data->expand);
 }
 
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8672d07..8013a1b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -76,7 +76,7 @@ static int update_some(const unsigned char *sha1, struct strbuf *base,
 
 	len = base->len + strlen(pathname);
 	ce = xcalloc(1, cache_entry_size(len));
-	hashcpy(ce->sha1, sha1);
+	hashcpy(ce->oid.hash, sha1);
 	memcpy(ce->name, base->buf, base->len);
 	memcpy(ce->name + base->len, pathname, len - base->len);
 	ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
@@ -92,7 +92,7 @@ static int update_some(const unsigned char *sha1, struct strbuf *base,
 	if (pos >= 0) {
 		struct cache_entry *old = active_cache[pos];
 		if (ce->ce_mode == old->ce_mode &&
-		    !hashcmp(ce->sha1, old->sha1)) {
+		    !oidcmp(&ce->oid, &old->oid)) {
 			old->ce_flags |= CE_UPDATE;
 			free(ce);
 			return 0;
@@ -175,9 +175,9 @@ static int checkout_merged(int pos, struct checkout *state)
 	const char *path = ce->name;
 	mmfile_t ancestor, ours, theirs;
 	int status;
-	unsigned char sha1[20];
+	struct object_id oid;
 	mmbuffer_t result_buf;
-	unsigned char threeway[3][20];
+	struct object_id threeway[3];
 	unsigned mode = 0;
 
 	memset(threeway, 0, sizeof(threeway));
@@ -186,18 +186,18 @@ static int checkout_merged(int pos, struct checkout *state)
 		stage = ce_stage(ce);
 		if (!stage || strcmp(path, ce->name))
 			break;
-		hashcpy(threeway[stage - 1], ce->sha1);
+		oidcpy(&threeway[stage - 1], &ce->oid);
 		if (stage == 2)
 			mode = create_ce_mode(ce->ce_mode);
 		pos++;
 		ce = active_cache[pos];
 	}
-	if (is_null_sha1(threeway[1]) || is_null_sha1(threeway[2]))
+	if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2]))
 		return error(_("path '%s' does not have necessary versions"), path);
 
-	read_mmblob(&ancestor, threeway[0]);
-	read_mmblob(&ours, threeway[1]);
-	read_mmblob(&theirs, threeway[2]);
+	read_mmblob(&ancestor, &threeway[0]);
+	read_mmblob(&ours, &threeway[1]);
+	read_mmblob(&theirs, &threeway[2]);
 
 	/*
 	 * NEEDSWORK: re-create conflicts from merges with
@@ -226,9 +226,9 @@ static int checkout_merged(int pos, struct checkout *state)
 	 * object database even when it may contain conflicts).
 	 */
 	if (write_sha1_file(result_buf.ptr, result_buf.size,
-			    blob_type, sha1))
+			    blob_type, oid.hash))
 		die(_("Unable to add merge result for '%s'"), path);
-	ce = make_cache_entry(mode, sha1, path, 2, 0);
+	ce = make_cache_entry(mode, oid.hash, path, 2, 0);
 	if (!ce)
 		die(_("make_cache_entry failed for path '%s'"), path);
 	status = checkout_entry(ce, state, NULL);
@@ -241,7 +241,7 @@ static int checkout_paths(const struct checkout_opts *opts,
 	int pos;
 	struct checkout state;
 	static char *ps_matched;
-	unsigned char rev[20];
+	struct object_id rev;
 	struct commit *head;
 	int errs = 0;
 	struct lock_file *lock_file;
@@ -374,8 +374,8 @@ static int checkout_paths(const struct checkout_opts *opts,
 	if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 		die(_("unable to write new index file"));
 
-	read_ref_full("HEAD", 0, rev, NULL);
-	head = lookup_commit_reference_gently(rev, 1);
+	read_ref_full("HEAD", 0, rev.hash, NULL);
+	head = lookup_commit_reference_gently(rev.hash, 1);
 
 	errs |= post_checkout_hook(head, head, 0);
 	return errs;
@@ -808,11 +808,11 @@ static int switch_branches(const struct checkout_opts *opts,
 	int ret = 0;
 	struct branch_info old;
 	void *path_to_free;
-	unsigned char rev[20];
+	struct object_id rev;
 	int flag, writeout_error = 0;
 	memset(&old, 0, sizeof(old));
-	old.path = path_to_free = resolve_refdup("HEAD", 0, rev, &flag);
-	old.commit = lookup_commit_reference_gently(rev, 1);
+	old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
+	old.commit = lookup_commit_reference_gently(rev.hash, 1);
 	if (!(flag & REF_ISSYMREF))
 		old.path = NULL;
 
@@ -860,7 +860,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
 struct tracking_name_data {
 	/* const */ char *src_ref;
 	char *dst_ref;
-	unsigned char *dst_sha1;
+	struct object_id *dst_oid;
 	int unique;
 };
 
@@ -871,7 +871,7 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
 	memset(&query, 0, sizeof(struct refspec));
 	query.src = cb->src_ref;
 	if (remote_find_tracking(remote, &query) ||
-	    get_sha1(query.dst, cb->dst_sha1)) {
+	    get_oid(query.dst, cb->dst_oid)) {
 		free(query.dst);
 		return 0;
 	}
@@ -884,13 +884,13 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
 	return 0;
 }
 
-static const char *unique_tracking_name(const char *name, unsigned char *sha1)
+static const char *unique_tracking_name(const char *name, struct object_id *oid)
 {
 	struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
 	char src_ref[PATH_MAX];
 	snprintf(src_ref, PATH_MAX, "refs/heads/%s", name);
 	cb_data.src_ref = src_ref;
-	cb_data.dst_sha1 = sha1;
+	cb_data.dst_oid = oid;
 	for_each_remote(check_tracking_name, &cb_data);
 	if (cb_data.unique)
 		return cb_data.dst_ref;
@@ -902,12 +902,12 @@ static int parse_branchname_arg(int argc, const char **argv,
 				int dwim_new_local_branch_ok,
 				struct branch_info *new,
 				struct checkout_opts *opts,
-				unsigned char rev[20])
+				struct object_id *rev)
 {
 	struct tree **source_tree = &opts->source_tree;
 	const char **new_branch = &opts->new_branch;
 	int argcount = 0;
-	unsigned char branch_rev[20];
+	struct object_id branch_rev;
 	const char *arg;
 	int dash_dash_pos;
 	int has_dash_dash = 0;
@@ -973,7 +973,7 @@ static int parse_branchname_arg(int argc, const char **argv,
 	if (!strcmp(arg, "-"))
 		arg = "@{-1}";
 
-	if (get_sha1_mb(arg, rev)) {
+	if (get_oid_mb(arg, rev)) {
 		/*
 		 * Either case (3) or (4), with <something> not being
 		 * a commit, or an attempt to use case (1) with an
@@ -1022,15 +1022,15 @@ static int parse_branchname_arg(int argc, const char **argv,
 	setup_branch_path(new);
 
 	if (!check_refname_format(new->path, 0) &&
-	    !read_ref(new->path, branch_rev))
-		hashcpy(rev, branch_rev);
+	    !read_ref(new->path, branch_rev.hash))
+		oidcpy(rev, &branch_rev);
 	else
 		new->path = NULL; /* not an existing branch */
 
-	new->commit = lookup_commit_reference_gently(rev, 1);
+	new->commit = lookup_commit_reference_gently(rev->hash, 1);
 	if (!new->commit) {
 		/* not a commit */
-		*source_tree = parse_tree_indirect(rev);
+		*source_tree = parse_tree_indirect(rev->hash);
 	} else {
 		parse_commit_or_die(new->commit);
 		*source_tree = new->commit->tree;
@@ -1108,9 +1108,9 @@ static int checkout_branch(struct checkout_opts *opts,
 
 	if (new->path && !opts->force_detach && !opts->new_branch &&
 	    !opts->ignore_other_worktrees) {
-		unsigned char sha1[20];
+		struct object_id oid;
 		int flag;
-		char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
+		char *head_ref = resolve_refdup("HEAD", 0, oid.hash, &flag);
 		if (head_ref &&
 		    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
 			die_if_checked_out(new->path, 1);
@@ -1118,11 +1118,11 @@ static int checkout_branch(struct checkout_opts *opts,
 	}
 
 	if (!new->commit && opts->new_branch) {
-		unsigned char rev[20];
+		struct object_id rev;
 		int flag;
 
-		if (!read_ref_full("HEAD", 0, rev, &flag) &&
-		    (flag & REF_ISSYMREF) && is_null_sha1(rev))
+		if (!read_ref_full("HEAD", 0, rev.hash, &flag) &&
+		    (flag & REF_ISSYMREF) && is_null_oid(&rev))
 			return switch_unborn_to_new_branch(opts);
 	}
 	return switch_branches(opts, new);
@@ -1232,14 +1232,14 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	 * remote branches, erroring out for invalid or ambiguous cases.
 	 */
 	if (argc) {
-		unsigned char rev[20];
+		struct object_id rev;
 		int dwim_ok =
 			!opts.patch_mode &&
 			dwim_new_local_branch &&
 			opts.track == BRANCH_TRACK_UNSPECIFIED &&
 			!opts.new_branch;
 		int n = parse_branchname_arg(argc, argv, dwim_ok,
-					     &new, &opts, rev);
+					     &new, &opts, &rev);
 		argv += n;
 		argc -= n;
 	}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 8a674bc..6050172 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -40,8 +40,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 {
 	int i, got_tree = 0;
 	struct commit_list *parents = NULL;
-	unsigned char tree_sha1[20];
-	unsigned char commit_sha1[20];
+	struct object_id tree_oid;
+	struct object_id commit_oid;
 	struct strbuf buffer = STRBUF_INIT;
 
 	git_config(commit_tree_config, NULL);
@@ -52,13 +52,13 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!strcmp(arg, "-p")) {
-			unsigned char sha1[20];
+			struct object_id oid;
 			if (argc <= ++i)
 				usage(commit_tree_usage);
-			if (get_sha1_commit(argv[i], sha1))
+			if (get_sha1_commit(argv[i], oid.hash))
 				die("Not a valid object name %s", argv[i]);
-			assert_sha1_type(sha1, OBJ_COMMIT);
-			new_parent(lookup_commit(sha1), &parents);
+			assert_sha1_type(oid.hash, OBJ_COMMIT);
+			new_parent(lookup_commit(oid.hash), &parents);
 			continue;
 		}
 
@@ -105,7 +105,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 			continue;
 		}
 
-		if (get_sha1_tree(arg, tree_sha1))
+		if (get_sha1_tree(arg, tree_oid.hash))
 			die("Not a valid object name %s", arg);
 		if (got_tree)
 			die("Cannot give more than one trees");
@@ -117,13 +117,13 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 			die_errno("git commit-tree: failed to read");
 	}
 
-	if (commit_tree(buffer.buf, buffer.len, tree_sha1, parents,
-			commit_sha1, NULL, sign_commit)) {
+	if (commit_tree(buffer.buf, buffer.len, tree_oid.hash, parents,
+			commit_oid.hash, NULL, sign_commit)) {
 		strbuf_release(&buffer);
 		return 1;
 	}
 
-	printf("%s\n", sha1_to_hex(commit_sha1));
+	printf("%s\n", oid_to_hex(&commit_oid));
 	strbuf_release(&buffer);
 	return 0;
 }
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 2de272e..055dfdc 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -268,7 +268,7 @@ static void check_unreachable_object(struct object *obj)
 			if (!(f = fopen(filename, "w")))
 				die_errno("Could not open '%s'", filename);
 			if (obj->type == OBJ_BLOB) {
-				if (stream_blob_to_fd(fileno(f), obj->oid.hash, NULL, 1))
+				if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
 					die_errno("Could not write '%s'", filename);
 			} else
 				fprintf(f, "%s\n", describe_object(obj));
@@ -722,7 +722,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 			mode = active_cache[i]->ce_mode;
 			if (S_ISGITLINK(mode))
 				continue;
-			blob = lookup_blob(active_cache[i]->sha1);
+			blob = lookup_blob(active_cache[i]->oid.hash);
 			if (!blob)
 				continue;
 			obj = &blob->object;
diff --git a/builtin/grep.c b/builtin/grep.c
index ae73831..8887b6a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -398,7 +398,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 		if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
 			if (ce_stage(ce) || ce_intent_to_add(ce))
 				continue;
-			hit |= grep_sha1(opt, ce->sha1, ce->name, 0, ce->name);
+			hit |= grep_sha1(opt, ce->oid.hash, ce->name, 0,
+					 ce->name);
 		}
 		else
 			hit |= grep_file(opt, ce->name);
diff --git a/builtin/log.c b/builtin/log.c
index 49aa534..e6cab12 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -464,9 +464,9 @@ static void show_tagger(char *buf, int len, struct rev_info *rev)
 	strbuf_release(&out);
 }
 
-static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, const char *obj_name)
+static int show_blob_object(const struct object_id *oid, struct rev_info *rev, const char *obj_name)
 {
-	unsigned char sha1c[20];
+	struct object_id oidc;
 	struct object_context obj_context;
 	char *buf;
 	unsigned long size;
@@ -474,13 +474,13 @@ static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, con
 	fflush(rev->diffopt.file);
 	if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
 	    !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
-		return stream_blob_to_fd(1, sha1, NULL, 0);
+		return stream_blob_to_fd(1, oid, NULL, 0);
 
-	if (get_sha1_with_context(obj_name, 0, sha1c, &obj_context))
+	if (get_sha1_with_context(obj_name, 0, oidc.hash, &obj_context))
 		die(_("Not a valid object name %s"), obj_name);
 	if (!obj_context.path[0] ||
-	    !textconv_object(obj_context.path, obj_context.mode, sha1c, 1, &buf, &size))
-		return stream_blob_to_fd(1, sha1, NULL, 0);
+	    !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size))
+		return stream_blob_to_fd(1, oid, NULL, 0);
 
 	if (!buf)
 		die(_("git show %s: bad file"), obj_name);
@@ -489,15 +489,15 @@ static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, con
 	return 0;
 }
 
-static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
+static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 {
 	unsigned long size;
 	enum object_type type;
-	char *buf = read_sha1_file(sha1, &type, &size);
+	char *buf = read_sha1_file(oid->hash, &type, &size);
 	int offset = 0;
 
 	if (!buf)
-		return error(_("Could not read object %s"), sha1_to_hex(sha1));
+		return error(_("Could not read object %s"), oid_to_hex(oid));
 
 	assert(type == OBJ_TAG);
 	while (offset < size && buf[offset] != '\n') {
@@ -574,7 +574,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 		const char *name = objects[i].name;
 		switch (o->type) {
 		case OBJ_BLOB:
-			ret = show_blob_object(o->oid.hash, &rev, name);
+			ret = show_blob_object(&o->oid, &rev, name);
 			break;
 		case OBJ_TAG: {
 			struct tag *t = (struct tag *)o;
@@ -585,7 +585,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
 					t->tag,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
-			ret = show_tag_object(o->oid.hash, &rev);
+			ret = show_tag_object(&o->oid, &rev);
 			rev.shown_one = 1;
 			if (ret)
 				break;
@@ -1248,11 +1248,11 @@ static struct commit *get_base_commit(const char *base_commit,
 		if (upstream) {
 			struct commit_list *base_list;
 			struct commit *commit;
-			unsigned char sha1[20];
+			struct object_id oid;
 
-			if (get_sha1(upstream, sha1))
+			if (get_oid(upstream, &oid))
 				die(_("Failed to resolve '%s' as a valid ref."), upstream);
-			commit = lookup_commit_or_die(sha1, "upstream base");
+			commit = lookup_commit_or_die(oid.hash, "upstream base");
 			base_list = get_merge_bases_many(commit, total, list);
 			/* There should be one and only one merge base. */
 			if (!base_list || base_list->next)
@@ -1339,15 +1339,15 @@ static void prepare_bases(struct base_tree_info *bases,
 	 * and stuff them in bases structure.
 	 */
 	while ((commit = get_revision(&revs)) != NULL) {
-		unsigned char sha1[20];
+		struct object_id oid;
 		struct object_id *patch_id;
 		if (commit->util)
 			continue;
-		if (commit_patch_id(commit, &diffopt, sha1, 0))
+		if (commit_patch_id(commit, &diffopt, oid.hash, 0))
 			die(_("cannot get patch id"));
 		ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
 		patch_id = bases->patch_id + bases->nr_patch_id;
-		hashcpy(patch_id->hash, sha1);
+		oidcpy(patch_id, &oid);
 		bases->nr_patch_id++;
 	}
 }
@@ -1628,10 +1628,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			check_head = 1;
 
 		if (check_head) {
-			unsigned char sha1[20];
+			struct object_id oid;
 			const char *ref, *v;
 			ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
-						 sha1, NULL);
+						 oid.hash, NULL);
 			if (ref && skip_prefix(ref, "refs/heads/", &v))
 				branch_name = xstrdup(v);
 			else
@@ -1802,9 +1802,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
 static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
 {
-	unsigned char sha1[20];
-	if (get_sha1(arg, sha1) == 0) {
-		struct commit *commit = lookup_commit_reference(sha1);
+	struct object_id oid;
+	if (get_oid(arg, &oid) == 0) {
+		struct commit *commit = lookup_commit_reference(oid.hash);
 		if (commit) {
 			commit->object.flags |= flags;
 			add_pending_object(revs, &commit->object, arg);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 00ea91a..197f153 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -187,7 +187,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 		printf("%s%06o %s %d\t",
 		       tag,
 		       ce->ce_mode,
-		       find_unique_abbrev(ce->sha1,abbrev),
+		       find_unique_abbrev(ce->oid.hash,abbrev),
 		       ce_stage(ce));
 	}
 	write_eolinfo(ce, ce->name);
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 1c3427c..ce356b1 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -22,7 +22,7 @@ static int merge_entry(int pos, const char *path)
 		if (strcmp(ce->name, path))
 			break;
 		found++;
-		sha1_to_hex_r(hexbuf[stage], ce->sha1);
+		sha1_to_hex_r(hexbuf[stage], ce->oid.hash);
 		xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
 		arguments[stage] = hexbuf[stage];
 		arguments[stage + 4] = ownbuf[stage];
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 8c693e7..9bd1fd7 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -78,7 +78,7 @@ static void debug_stage(const char *label, const struct cache_entry *ce,
 	else
 		printf("%06o #%d %s %.8s\n",
 		       ce->ce_mode, ce_stage(ce), ce->name,
-		       sha1_to_hex(ce->sha1));
+		       oid_to_hex(&ce->oid));
 }
 
 static int debug_merge(const struct cache_entry * const *stages,
diff --git a/builtin/reset.c b/builtin/reset.c
index 9020ec6..5aa8607 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -39,7 +39,7 @@ static inline int is_merge(void)
 	return !access(git_path_merge_head(), F_OK);
 }
 
-static int reset_index(const unsigned char *sha1, int reset_type, int quiet)
+static int reset_index(const struct object_id *oid, int reset_type, int quiet)
 {
 	int nr = 1;
 	struct tree_desc desc[2];
@@ -69,22 +69,22 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet)
 	read_cache_unmerged();
 
 	if (reset_type == KEEP) {
-		unsigned char head_sha1[20];
-		if (get_sha1("HEAD", head_sha1))
+		struct object_id head_oid;
+		if (get_oid("HEAD", &head_oid))
 			return error(_("You do not have a valid HEAD."));
-		if (!fill_tree_descriptor(desc, head_sha1))
+		if (!fill_tree_descriptor(desc, head_oid.hash))
 			return error(_("Failed to find tree of HEAD."));
 		nr++;
 		opts.fn = twoway_merge;
 	}
 
-	if (!fill_tree_descriptor(desc + nr - 1, sha1))
-		return error(_("Failed to find tree of %s."), sha1_to_hex(sha1));
+	if (!fill_tree_descriptor(desc + nr - 1, oid->hash))
+		return error(_("Failed to find tree of %s."), oid_to_hex(oid));
 	if (unpack_trees(nr, desc, &opts))
 		return -1;
 
 	if (reset_type == MIXED || reset_type == HARD) {
-		tree = parse_tree_indirect(sha1);
+		tree = parse_tree_indirect(oid->hash);
 		prime_cache_tree(&the_index, tree);
 	}
 
@@ -143,7 +143,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
 }
 
 static int read_from_tree(const struct pathspec *pathspec,
-			  unsigned char *tree_sha1,
+			  struct object_id *tree_oid,
 			  int intent_to_add)
 {
 	struct diff_options opt;
@@ -154,7 +154,7 @@ static int read_from_tree(const struct pathspec *pathspec,
 	opt.format_callback = update_index_from_diff;
 	opt.format_callback_data = &intent_to_add;
 
-	if (do_diff_cache(tree_sha1, &opt))
+	if (do_diff_cache(tree_oid->hash, &opt))
 		return 1;
 	diffcore_std(&opt);
 	diff_flush(&opt);
@@ -191,7 +191,7 @@ static void parse_args(struct pathspec *pathspec,
 		       const char **rev_ret)
 {
 	const char *rev = "HEAD";
-	unsigned char unused[20];
+	struct object_id unused;
 	/*
 	 * Possible arguments are:
 	 *
@@ -216,8 +216,8 @@ static void parse_args(struct pathspec *pathspec,
 		 * has to be unambiguous. If there is a single argument, it
 		 * can not be a tree
 		 */
-		else if ((!argv[1] && !get_sha1_committish(argv[0], unused)) ||
-			 (argv[1] && !get_sha1_treeish(argv[0], unused))) {
+		else if ((!argv[1] && !get_sha1_committish(argv[0], unused.hash)) ||
+			 (argv[1] && !get_sha1_treeish(argv[0], unused.hash))) {
 			/*
 			 * Ok, argv[0] looks like a commit/tree; it should not
 			 * be a filename.
@@ -241,24 +241,24 @@ static void parse_args(struct pathspec *pathspec,
 		       prefix, argv);
 }
 
-static int reset_refs(const char *rev, const unsigned char *sha1)
+static int reset_refs(const char *rev, const struct object_id *oid)
 {
 	int update_ref_status;
 	struct strbuf msg = STRBUF_INIT;
-	unsigned char *orig = NULL, sha1_orig[20],
-		*old_orig = NULL, sha1_old_orig[20];
+	struct object_id *orig = NULL, oid_orig,
+		*old_orig = NULL, oid_old_orig;
 
-	if (!get_sha1("ORIG_HEAD", sha1_old_orig))
-		old_orig = sha1_old_orig;
-	if (!get_sha1("HEAD", sha1_orig)) {
-		orig = sha1_orig;
+	if (!get_oid("ORIG_HEAD", &oid_old_orig))
+		old_orig = &oid_old_orig;
+	if (!get_oid("HEAD", &oid_orig)) {
+		orig = &oid_orig;
 		set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
-		update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
+		update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
 			   UPDATE_REFS_MSG_ON_ERR);
 	} else if (old_orig)
-		delete_ref("ORIG_HEAD", old_orig, 0);
+		delete_ref("ORIG_HEAD", old_orig->hash, 0);
 	set_reflog_message(&msg, "updating HEAD", rev);
-	update_ref_status = update_ref(msg.buf, "HEAD", sha1, orig, 0,
+	update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0,
 				       UPDATE_REFS_MSG_ON_ERR);
 	strbuf_release(&msg);
 	return update_ref_status;
@@ -357,15 +357,15 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 		hold_locked_index(lock, 1);
 		if (reset_type == MIXED) {
 			int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
-			if (read_from_tree(&pathspec, oid.hash, intent_to_add))
+			if (read_from_tree(&pathspec, &oid, intent_to_add))
 				return 1;
 			if (get_git_work_tree())
 				refresh_index(&the_index, flags, NULL, NULL,
 					      _("Unstaged changes after reset:"));
 		} else {
-			int err = reset_index(oid.hash, reset_type, quiet);
+			int err = reset_index(&oid, reset_type, quiet);
 			if (reset_type == KEEP && !err)
-				err = reset_index(oid.hash, MIXED, quiet);
+				err = reset_index(&oid, MIXED, quiet);
 			if (err)
 				die(_("Could not reset index file to revision '%s'."), rev);
 		}
@@ -377,7 +377,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 	if (!pathspec.nr && !unborn) {
 		/* Any resets without paths update HEAD to the head being
 		 * switched to, saving the previous head in ORIG_HEAD before. */
-		update_ref_status = reset_refs(rev, oid.hash);
+		update_ref_status = reset_refs(rev, &oid);
 
 		if (reset_type == HARD && !update_ref_status && !quiet)
 			print_new_head_line(lookup_commit_reference(oid.hash));
diff --git a/builtin/rm.c b/builtin/rm.c
index b2fee3e..3f3e24e 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -107,7 +107,7 @@ static int check_submodules_use_gitfiles(void)
 	return errs;
 }
 
-static int check_local_mod(unsigned char *head, int index_only)
+static int check_local_mod(struct object_id *head, int index_only)
 {
 	/*
 	 * Items in list are already sorted in the cache order,
@@ -123,13 +123,13 @@ static int check_local_mod(unsigned char *head, int index_only)
 	struct string_list files_submodule = STRING_LIST_INIT_NODUP;
 	struct string_list files_local = STRING_LIST_INIT_NODUP;
 
-	no_head = is_null_sha1(head);
+	no_head = is_null_oid(head);
 	for (i = 0; i < list.nr; i++) {
 		struct stat st;
 		int pos;
 		const struct cache_entry *ce;
 		const char *name = list.entry[i].name;
-		unsigned char sha1[20];
+		struct object_id oid;
 		unsigned mode;
 		int local_changes = 0;
 		int staged_changes = 0;
@@ -197,9 +197,9 @@ static int check_local_mod(unsigned char *head, int index_only)
 		 * way as changed from the HEAD.
 		 */
 		if (no_head
-		     || get_tree_entry(head, name, sha1, &mode)
+		     || get_tree_entry(head->hash, name, oid.hash, &mode)
 		     || ce->ce_mode != create_ce_mode(mode)
-		     || hashcmp(ce->sha1, sha1))
+		     || oidcmp(&ce->oid, &oid))
 			staged_changes = 1;
 
 		/*
@@ -351,10 +351,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 	 * report no changes unless forced.
 	 */
 	if (!force) {
-		unsigned char sha1[20];
-		if (get_sha1("HEAD", sha1))
-			hashclr(sha1);
-		if (check_local_mod(sha1, index_only))
+		struct object_id oid;
+		if (get_oid("HEAD", &oid))
+			oidclr(&oid);
+		if (check_local_mod(&oid, index_only))
 			exit(1);
 	} else if (!index_only) {
 		if (check_submodules_use_gitfiles())
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9d79f19..7b8ddfe 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -296,7 +296,8 @@ static int module_list(int argc, const char **argv, const char *prefix)
 		if (ce_stage(ce))
 			printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1));
 		else
-			printf("%06o %s %d\t", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce));
+			printf("%06o %s %d\t", ce->ce_mode,
+			       oid_to_hex(&ce->oid), ce_stage(ce));
 
 		utf8_fprintf(stdout, "%s\n", ce->name);
 	}
@@ -790,7 +791,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
-			sha1_to_hex(ce->sha1), ce_stage(ce),
+			oid_to_hex(&ce->oid), ce_stage(ce),
 			needs_cloning, ce->name);
 	string_list_append(&suc->projectlines, sb.buf);
 
diff --git a/builtin/update-index.c b/builtin/update-index.c
index ba04b19..44fb2e4 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -275,7 +275,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
 	fill_stat_cache_info(ce, st);
 	ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
 
-	if (index_path(ce->sha1, path, st,
+	if (index_path(ce->oid.hash, path, st,
 		       info_only ? 0 : HASH_WRITE_OBJECT)) {
 		free(ce);
 		return -1;
@@ -312,7 +312,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
  */
 static int process_directory(const char *path, int len, struct stat *st)
 {
-	unsigned char sha1[20];
+	struct object_id oid;
 	int pos = cache_name_pos(path, len);
 
 	/* Exact match: file or existing gitlink */
@@ -321,7 +321,7 @@ static int process_directory(const char *path, int len, struct stat *st)
 		if (S_ISGITLINK(ce->ce_mode)) {
 
 			/* Do nothing to the index if there is no HEAD! */
-			if (resolve_gitlink_ref(path, "HEAD", sha1) < 0)
+			if (resolve_gitlink_ref(path, "HEAD", oid.hash) < 0)
 				return 0;
 
 			return add_one_path(ce, path, len, st);
@@ -347,7 +347,7 @@ static int process_directory(const char *path, int len, struct stat *st)
 	}
 
 	/* No match - should we add it as a gitlink? */
-	if (!resolve_gitlink_ref(path, "HEAD", sha1))
+	if (!resolve_gitlink_ref(path, "HEAD", oid.hash))
 		return add_one_path(NULL, path, len, st);
 
 	/* Error out. */
@@ -390,7 +390,7 @@ static int process_path(const char *path)
 	return add_one_path(ce, path, len, &st);
 }
 
-static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
+static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
 			 const char *path, int stage)
 {
 	int size, len, option;
@@ -403,7 +403,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
 	size = cache_entry_size(len);
 	ce = xcalloc(1, size);
 
-	hashcpy(ce->sha1, sha1);
+	oidcpy(&ce->oid, oid);
 	memcpy(ce->name, path, len);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = len;
@@ -487,7 +487,7 @@ static void read_index_info(int nul_term_line)
 	while (getline_fn(&buf, stdin) != EOF) {
 		char *ptr, *tab;
 		char *path_name;
-		unsigned char sha1[20];
+		struct object_id oid;
 		unsigned int mode;
 		unsigned long ul;
 		int stage;
@@ -516,7 +516,7 @@ static void read_index_info(int nul_term_line)
 		mode = ul;
 
 		tab = strchr(ptr, '\t');
-		if (!tab || tab - ptr < 41)
+		if (!tab || tab - ptr < GIT_SHA1_HEXSZ + 1)
 			goto bad_line;
 
 		if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
@@ -529,7 +529,8 @@ static void read_index_info(int nul_term_line)
 			ptr = tab + 1; /* point at the head of path */
 		}
 
-		if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
+		if (get_oid_hex(tab - GIT_SHA1_HEXSZ, &oid) ||
+			tab[-(GIT_SHA1_HEXSZ + 1)] != ' ')
 			goto bad_line;
 
 		path_name = ptr;
@@ -557,8 +558,8 @@ static void read_index_info(int nul_term_line)
 			 * ptr[-1] points at tab,
 			 * ptr[-41] is at the beginning of sha1
 			 */
-			ptr[-42] = ptr[-1] = 0;
-			if (add_cacheinfo(mode, sha1, path_name, stage))
+			ptr[-(GIT_SHA1_HEXSZ + 2)] = ptr[-1] = 0;
+			if (add_cacheinfo(mode, &oid, path_name, stage))
 				die("git update-index: unable to update %s",
 				    path_name);
 		}
@@ -576,19 +577,19 @@ static const char * const update_index_usage[] = {
 	NULL
 };
 
-static unsigned char head_sha1[20];
-static unsigned char merge_head_sha1[20];
+static struct object_id head_oid;
+static struct object_id merge_head_oid;
 
 static struct cache_entry *read_one_ent(const char *which,
-					unsigned char *ent, const char *path,
+					struct object_id *ent, const char *path,
 					int namelen, int stage)
 {
 	unsigned mode;
-	unsigned char sha1[20];
+	struct object_id oid;
 	int size;
 	struct cache_entry *ce;
 
-	if (get_tree_entry(ent, path, sha1, &mode)) {
+	if (get_tree_entry(ent->hash, path, oid.hash, &mode)) {
 		if (which)
 			error("%s: not in %s branch.", path, which);
 		return NULL;
@@ -601,7 +602,7 @@ static struct cache_entry *read_one_ent(const char *which,
 	size = cache_entry_size(namelen);
 	ce = xcalloc(1, size);
 
-	hashcpy(ce->sha1, sha1);
+	oidcpy(&ce->oid, &oid);
 	memcpy(ce->name, path, namelen);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = namelen;
@@ -651,14 +652,14 @@ static int unresolve_one(const char *path)
 	 * stuff HEAD version in stage #2,
 	 * stuff MERGE_HEAD version in stage #3.
 	 */
-	ce_2 = read_one_ent("our", head_sha1, path, namelen, 2);
-	ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3);
+	ce_2 = read_one_ent("our", &head_oid, path, namelen, 2);
+	ce_3 = read_one_ent("their", &merge_head_oid, path, namelen, 3);
 
 	if (!ce_2 || !ce_3) {
 		ret = -1;
 		goto free_return;
 	}
-	if (!hashcmp(ce_2->sha1, ce_3->sha1) &&
+	if (!oidcmp(&ce_2->oid, &ce_3->oid) &&
 	    ce_2->ce_mode == ce_3->ce_mode) {
 		fprintf(stderr, "%s: identical in both, skipping.\n",
 			path);
@@ -683,9 +684,9 @@ static int unresolve_one(const char *path)
 
 static void read_head_pointers(void)
 {
-	if (read_ref("HEAD", head_sha1))
+	if (read_ref("HEAD", head_oid.hash))
 		die("No HEAD -- no initial commit yet?");
-	if (read_ref("MERGE_HEAD", merge_head_sha1)) {
+	if (read_ref("MERGE_HEAD", merge_head_oid.hash)) {
 		fprintf(stderr, "Not in the middle of a merge.\n");
 		exit(0);
 	}
@@ -725,7 +726,7 @@ static int do_reupdate(int ac, const char **av,
 		       PATHSPEC_PREFER_CWD,
 		       prefix, av + 1);
 
-	if (read_ref("HEAD", head_sha1))
+	if (read_ref("HEAD", head_oid.hash))
 		/* If there is no HEAD, that means it is an initial
 		 * commit.  Update everything in the index.
 		 */
@@ -740,10 +741,10 @@ static int do_reupdate(int ac, const char **av,
 		if (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL))
 			continue;
 		if (has_head)
-			old = read_one_ent(NULL, head_sha1,
+			old = read_one_ent(NULL, &head_oid,
 					   ce->name, ce_namelen(ce), 0);
 		if (old && ce->ce_mode == old->ce_mode &&
-		    !hashcmp(ce->sha1, old->sha1)) {
+		    !oidcmp(&ce->oid, &old->oid)) {
 			free(old);
 			continue; /* unchanged */
 		}
@@ -807,7 +808,7 @@ static int resolve_undo_clear_callback(const struct option *opt,
 
 static int parse_new_style_cacheinfo(const char *arg,
 				     unsigned int *mode,
-				     unsigned char sha1[],
+				     struct object_id *oid,
 				     const char **path)
 {
 	unsigned long ul;
@@ -822,21 +823,21 @@ static int parse_new_style_cacheinfo(const char *arg,
 		return -1; /* not a new-style cacheinfo */
 	*mode = ul;
 	endp++;
-	if (get_sha1_hex(endp, sha1) || endp[40] != ',')
+	if (get_oid_hex(endp, oid) || endp[GIT_SHA1_HEXSZ] != ',')
 		return -1;
-	*path = endp + 41;
+	*path = endp + GIT_SHA1_HEXSZ + 1;
 	return 0;
 }
 
 static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
 				const struct option *opt, int unset)
 {
-	unsigned char sha1[20];
+	struct object_id oid;
 	unsigned int mode;
 	const char *path;
 
-	if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, sha1, &path)) {
-		if (add_cacheinfo(mode, sha1, path, 0))
+	if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {
+		if (add_cacheinfo(mode, &oid, path, 0))
 			die("git update-index: --cacheinfo cannot add %s", path);
 		ctx->argv++;
 		ctx->argc--;
@@ -845,8 +846,8 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
 	if (ctx->argc <= 3)
 		return error("option 'cacheinfo' expects <mode>,<sha1>,<path>");
 	if (strtoul_ui(*++ctx->argv, 8, &mode) ||
-	    get_sha1_hex(*++ctx->argv, sha1) ||
-	    add_cacheinfo(mode, sha1, *++ctx->argv, 0))
+	    get_oid_hex(*++ctx->argv, &oid) ||
+	    add_cacheinfo(mode, &oid, *++ctx->argv, 0))
 		die("git update-index: --cacheinfo cannot add %s", *ctx->argv);
 	ctx->argc -= 3;
 	return 0;
diff --git a/cache-tree.c b/cache-tree.c
index f28b1f4..345ea35 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -168,7 +168,7 @@ static int verify_cache(struct cache_entry **cache,
 				break;
 			}
 			fprintf(stderr, "%s: unmerged (%s)\n",
-				ce->name, sha1_to_hex(ce->sha1));
+				ce->name, oid_to_hex(&ce->oid));
 		}
 	}
 	if (funny)
@@ -349,7 +349,7 @@ static int update_one(struct cache_tree *it,
 			}
 		}
 		else {
-			sha1 = ce->sha1;
+			sha1 = ce->oid.hash;
 			mode = ce->ce_mode;
 			entlen = pathlen - baselen;
 			i++;
diff --git a/cache.h b/cache.h
index 3556326..ee04430 100644
--- a/cache.h
+++ b/cache.h
@@ -173,7 +173,7 @@ struct cache_entry {
 	unsigned int ce_flags;
 	unsigned int ce_namelen;
 	unsigned int index;	/* for link extension */
-	unsigned char sha1[20];
+	struct object_id oid;
 	char name[FLEX_ARRAY]; /* more */
 };
 
@@ -1231,7 +1231,7 @@ extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
 extern char *oid_to_hex(const struct object_id *oid);	/* same static buffer as sha1_to_hex */
 
 extern int interpret_branch_name(const char *str, int len, struct strbuf *);
-extern int get_sha1_mb(const char *str, unsigned char *sha1);
+extern int get_oid_mb(const char *str, struct object_id *oid);
 
 extern int validate_headref(const char *ref);
 
diff --git a/diff-lib.c b/diff-lib.c
index bc49c70..3007c85 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -155,7 +155,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 				if (2 <= stage) {
 					int mode = nce->ce_mode;
 					num_compare_stages++;
-					hashcpy(dpath->parent[stage-2].oid.hash, nce->sha1);
+					oidcpy(&dpath->parent[stage - 2].oid,
+					       &nce->oid);
 					dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
 					dpath->parent[stage-2].status =
 						DIFF_STATUS_MODIFIED;
@@ -209,7 +210,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 					continue;
 				}
 				diff_addremove(&revs->diffopt, '-', ce->ce_mode,
-					       ce->sha1, !is_null_sha1(ce->sha1),
+					       ce->oid.hash,
+					       !is_null_oid(&ce->oid),
 					       ce->name, 0);
 				continue;
 			}
@@ -225,8 +227,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 				continue;
 		}
 		oldmode = ce->ce_mode;
-		old_sha1 = ce->sha1;
-		new_sha1 = changed ? null_sha1 : ce->sha1;
+		old_sha1 = ce->oid.hash;
+		new_sha1 = changed ? null_sha1 : ce->oid.hash;
 		diff_change(&revs->diffopt, oldmode, newmode,
 			    old_sha1, new_sha1,
 			    !is_null_sha1(old_sha1),
@@ -261,7 +263,7 @@ static int get_stat_data(const struct cache_entry *ce,
 			 int cached, int match_missing,
 			 unsigned *dirty_submodule, struct diff_options *diffopt)
 {
-	const unsigned char *sha1 = ce->sha1;
+	const unsigned char *sha1 = ce->oid.hash;
 	unsigned int mode = ce->ce_mode;
 
 	if (!cached && !ce_uptodate(ce)) {
@@ -324,12 +326,13 @@ static int show_modified(struct rev_info *revs,
 			  &dirty_submodule, &revs->diffopt) < 0) {
 		if (report_missing)
 			diff_index_show_file(revs, "-", old,
-					     old->sha1, 1, old->ce_mode, 0);
+					     old->oid.hash, 1, old->ce_mode,
+					     0);
 		return -1;
 	}
 
 	if (revs->combine_merges && !cached &&
-	    (hashcmp(sha1, old->sha1) || hashcmp(old->sha1, new->sha1))) {
+	    (hashcmp(sha1, old->oid.hash) || oidcmp(&old->oid, &new->oid))) {
 		struct combine_diff_path *p;
 		int pathlen = ce_namelen(new);
 
@@ -343,22 +346,22 @@ static int show_modified(struct rev_info *revs,
 		memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
 		p->parent[0].status = DIFF_STATUS_MODIFIED;
 		p->parent[0].mode = new->ce_mode;
-		hashcpy(p->parent[0].oid.hash, new->sha1);
+		oidcpy(&p->parent[0].oid, &new->oid);
 		p->parent[1].status = DIFF_STATUS_MODIFIED;
 		p->parent[1].mode = old->ce_mode;
-		hashcpy(p->parent[1].oid.hash, old->sha1);
+		oidcpy(&p->parent[1].oid, &old->oid);
 		show_combined_diff(p, 2, revs->dense_combined_merges, revs);
 		free(p);
 		return 0;
 	}
 
 	oldmode = old->ce_mode;
-	if (mode == oldmode && !hashcmp(sha1, old->sha1) && !dirty_submodule &&
+	if (mode == oldmode && !hashcmp(sha1, old->oid.hash) && !dirty_submodule &&
 	    !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
 		return 0;
 
 	diff_change(&revs->diffopt, oldmode, mode,
-		    old->sha1, sha1, 1, !is_null_sha1(sha1),
+		    old->oid.hash, sha1, 1, !is_null_sha1(sha1),
 		    old->name, 0, dirty_submodule);
 	return 0;
 }
@@ -392,7 +395,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
 		struct diff_filepair *pair;
 		pair = diff_unmerge(&revs->diffopt, idx->name);
 		if (tree)
-			fill_filespec(pair->one, tree->sha1, 1, tree->ce_mode);
+			fill_filespec(pair->one, tree->oid.hash, 1,
+				      tree->ce_mode);
 		return;
 	}
 
@@ -408,7 +412,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
 	 * Something removed from the tree?
 	 */
 	if (!idx) {
-		diff_index_show_file(revs, "-", tree, tree->sha1, 1, tree->ce_mode, 0);
+		diff_index_show_file(revs, "-", tree, tree->oid.hash, 1,
+				     tree->ce_mode, 0);
 		return;
 	}
 
diff --git a/diff.c b/diff.c
index b4310f8..c6da383 100644
--- a/diff.c
+++ b/diff.c
@@ -2703,7 +2703,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
 	 * This is not the sha1 we are looking for, or
 	 * unreusable because it is not a regular file.
 	 */
-	if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode))
+	if (hashcmp(sha1, ce->oid.hash) || !S_ISREG(ce->ce_mode))
 		return 0;
 
 	/*
diff --git a/dir.c b/dir.c
index 0ea235f..9e09bcb 100644
--- a/dir.c
+++ b/dir.c
@@ -525,7 +525,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
 		return NULL;
 	if (!ce_skip_worktree(active_cache[pos]))
 		return NULL;
-	data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
+	data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
 	if (!data || type != OBJ_BLOB) {
 		free(data);
 		return NULL;
@@ -533,7 +533,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
 	*size = xsize_t(sz);
 	if (sha1_stat) {
 		memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
-		hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
+		hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
 	}
 	return data;
 }
@@ -713,7 +713,8 @@ static int add_excludes(const char *fname, const char *base, int baselen,
 				 !ce_stage(active_cache[pos]) &&
 				 ce_uptodate(active_cache[pos]) &&
 				 !would_convert_to_git(fname))
-				hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
+				hashcpy(sha1_stat->sha1,
+					active_cache[pos]->oid.hash);
 			else
 				hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
 			fill_stat_data(&sha1_stat->stat, &st);
diff --git a/entry.c b/entry.c
index 519e042..c6eea24 100644
--- a/entry.c
+++ b/entry.c
@@ -82,7 +82,7 @@ static int create_file(const char *path, unsigned int mode)
 static void *read_blob_entry(const struct cache_entry *ce, unsigned long *size)
 {
 	enum object_type type;
-	void *new = read_sha1_file(ce->sha1, &type, size);
+	void *new = read_sha1_file(ce->oid.hash, &type, size);
 
 	if (new) {
 		if (type == OBJ_BLOB)
@@ -127,7 +127,7 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path,
 	if (fd < 0)
 		return -1;
 
-	result |= stream_blob_to_fd(fd, ce->sha1, filter, 1);
+	result |= stream_blob_to_fd(fd, &ce->oid, filter, 1);
 	*fstat_done = fstat_output(fd, state, statbuf);
 	result |= close(fd);
 
@@ -148,7 +148,8 @@ static int write_entry(struct cache_entry *ce,
 	struct stat st;
 
 	if (ce_mode_s_ifmt == S_IFREG) {
-		struct stream_filter *filter = get_stream_filter(ce->name, ce->sha1);
+		struct stream_filter *filter = get_stream_filter(ce->name,
+								 ce->oid.hash);
 		if (filter &&
 		    !streaming_write_entry(ce, path, filter,
 					   state, to_tempfile,
@@ -162,7 +163,7 @@ static int write_entry(struct cache_entry *ce,
 		new = read_blob_entry(ce, &size);
 		if (!new)
 			return error("unable to read sha1 file of %s (%s)",
-				path, sha1_to_hex(ce->sha1));
+				path, oid_to_hex(&ce->oid));
 
 		if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
 			ret = symlink(new, path);
diff --git a/merge-recursive.c b/merge-recursive.c
index e349126..3750d25 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -382,7 +382,7 @@ static struct string_list *get_unmerged(void)
 		}
 		e = item->util;
 		e->stages[ce_stage(ce)].mode = ce->ce_mode;
-		hashcpy(e->stages[ce_stage(ce)].oid.hash, ce->sha1);
+		oidcpy(&e->stages[ce_stage(ce)].oid, &ce->oid);
 	}
 
 	return unmerged;
@@ -910,9 +910,9 @@ static int merge_3way(struct merge_options *o,
 		name2 = mkpathdup("%s", branch2);
 	}
 
-	read_mmblob(&orig, one->oid.hash);
-	read_mmblob(&src1, a->oid.hash);
-	read_mmblob(&src2, b->oid.hash);
+	read_mmblob(&orig, &one->oid);
+	read_mmblob(&src1, &a->oid);
+	read_mmblob(&src2, &b->oid);
 
 	merge_status = ll_merge(result_buf, a->path, &orig, base_name,
 				&src1, name1, &src2, name2, &ll_opts);
diff --git a/notes-merge.c b/notes-merge.c
index 97fc42f..b353628 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -12,7 +12,7 @@
 #include "notes-utils.h"
 
 struct notes_merge_pair {
-	unsigned char obj[20], base[20], local[20], remote[20];
+	struct object_id obj, base, local, remote;
 };
 
 void init_notes_merge_options(struct notes_merge_options *o)
@@ -75,7 +75,7 @@ static struct notes_merge_pair *find_notes_merge_pair_pos(
 	int i = last_index < len ? last_index : len - 1;
 	int prev_cmp = 0, cmp = -1;
 	while (i >= 0 && i < len) {
-		cmp = hashcmp(obj, list[i].obj);
+		cmp = hashcmp(obj, list[i].obj.hash);
 		if (!cmp) /* obj belongs @ i */
 			break;
 		else if (cmp < 0 && prev_cmp <= 0) /* obj belongs < i */
@@ -108,9 +108,10 @@ static struct notes_merge_pair *find_notes_merge_pair_pos(
 	return list + i;
 }
 
-static unsigned char uninitialized[20] =
+static struct object_id uninitialized = {
 	"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
-	"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+	"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+};
 
 static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
 						 const unsigned char *base,
@@ -149,25 +150,25 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
 		mp = find_notes_merge_pair_pos(changes, len, obj, 1, &occupied);
 		if (occupied) {
 			/* We've found an addition/deletion pair */
-			assert(!hashcmp(mp->obj, obj));
+			assert(!hashcmp(mp->obj.hash, obj));
 			if (is_null_oid(&p->one->oid)) { /* addition */
-				assert(is_null_sha1(mp->remote));
-				hashcpy(mp->remote, p->two->oid.hash);
+				assert(is_null_oid(&mp->remote));
+				oidcpy(&mp->remote, &p->two->oid);
 			} else if (is_null_oid(&p->two->oid)) { /* deletion */
-				assert(is_null_sha1(mp->base));
-				hashcpy(mp->base, p->one->oid.hash);
+				assert(is_null_oid(&mp->base));
+				oidcpy(&mp->base, &p->one->oid);
 			} else
 				assert(!"Invalid existing change recorded");
 		} else {
-			hashcpy(mp->obj, obj);
-			hashcpy(mp->base, p->one->oid.hash);
-			hashcpy(mp->local, uninitialized);
-			hashcpy(mp->remote, p->two->oid.hash);
+			hashcpy(mp->obj.hash, obj);
+			oidcpy(&mp->base, &p->one->oid);
+			oidcpy(&mp->local, &uninitialized);
+			oidcpy(&mp->remote, &p->two->oid);
 			len++;
 		}
 		trace_printf("\t\tStored remote change for %s: %.7s -> %.7s\n",
-		       sha1_to_hex(mp->obj), sha1_to_hex(mp->base),
-		       sha1_to_hex(mp->remote));
+		       oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
+		       oid_to_hex(&mp->remote));
 	}
 	diff_flush(&opt);
 	clear_pathspec(&opt.pathspec);
@@ -216,7 +217,7 @@ static void diff_tree_local(struct notes_merge_options *o,
 			continue;
 		}
 
-		assert(!hashcmp(mp->obj, obj));
+		assert(!hashcmp(mp->obj.hash, obj));
 		if (is_null_oid(&p->two->oid)) { /* deletion */
 			/*
 			 * Either this is a true deletion (1), or it is part
@@ -227,8 +228,8 @@ static void diff_tree_local(struct notes_merge_options *o,
 			 * (3) mp->local is uninitialized; set it to null_sha1
 			 *     (will be overwritten by following addition)
 			 */
-			if (!hashcmp(mp->local, uninitialized))
-				hashclr(mp->local);
+			if (!oidcmp(&mp->local, &uninitialized))
+				oidclr(&mp->local);
 		} else if (is_null_oid(&p->one->oid)) { /* addition */
 			/*
 			 * Either this is a true addition (1), or it is part
@@ -238,22 +239,22 @@ static void diff_tree_local(struct notes_merge_options *o,
 			 * (2) mp->local is uninitialized; set to p->two->sha1
 			 * (3) mp->local is null_sha1;     set to p->two->sha1
 			 */
-			assert(is_null_sha1(mp->local) ||
-			       !hashcmp(mp->local, uninitialized));
-			hashcpy(mp->local, p->two->oid.hash);
+			assert(is_null_oid(&mp->local) ||
+			       !oidcmp(&mp->local, &uninitialized));
+			oidcpy(&mp->local, &p->two->oid);
 		} else { /* modification */
 			/*
 			 * This is a true modification. p->one->sha1 shall
 			 * match mp->base, and mp->local shall be uninitialized.
 			 * Set mp->local to p->two->sha1.
 			 */
-			assert(!hashcmp(p->one->oid.hash, mp->base));
-			assert(!hashcmp(mp->local, uninitialized));
-			hashcpy(mp->local, p->two->oid.hash);
+			assert(!oidcmp(&p->one->oid, &mp->base));
+			assert(!oidcmp(&mp->local, &uninitialized));
+			oidcpy(&mp->local, &p->two->oid);
 		}
 		trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n",
-		       sha1_to_hex(mp->obj), sha1_to_hex(mp->base),
-		       sha1_to_hex(mp->local));
+		       oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
+		       oid_to_hex(&mp->local));
 	}
 	diff_flush(&opt);
 	clear_pathspec(&opt.pathspec);
@@ -343,11 +344,11 @@ static int ll_merge_in_worktree(struct notes_merge_options *o,
 	mmfile_t base, local, remote;
 	int status;
 
-	read_mmblob(&base, p->base);
-	read_mmblob(&local, p->local);
-	read_mmblob(&remote, p->remote);
+	read_mmblob(&base, &p->base);
+	read_mmblob(&local, &p->local);
+	read_mmblob(&remote, &p->remote);
 
-	status = ll_merge(&result_buf, sha1_to_hex(p->obj), &base, NULL,
+	status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL,
 			  &local, o->local_ref, &remote, o->remote_ref, NULL);
 
 	free(base.ptr);
@@ -357,7 +358,7 @@ static int ll_merge_in_worktree(struct notes_merge_options *o,
 	if ((status < 0) || !result_buf.ptr)
 		die("Failed to execute internal merge");
 
-	write_buf_to_worktree(p->obj, result_buf.ptr, result_buf.size);
+	write_buf_to_worktree(p->obj.hash, result_buf.ptr, result_buf.size);
 	free(result_buf.ptr);
 
 	return status;
@@ -372,51 +373,52 @@ static int merge_one_change_manual(struct notes_merge_options *o,
 
 	trace_printf("\t\t\tmerge_one_change_manual(obj = %.7s, base = %.7s, "
 	       "local = %.7s, remote = %.7s)\n",
-	       sha1_to_hex(p->obj), sha1_to_hex(p->base),
-	       sha1_to_hex(p->local), sha1_to_hex(p->remote));
+	       oid_to_hex(&p->obj), oid_to_hex(&p->base),
+	       oid_to_hex(&p->local), oid_to_hex(&p->remote));
 
 	/* add "Conflicts:" section to commit message first time through */
 	if (!o->has_worktree)
 		strbuf_addstr(&(o->commit_msg), "\n\nConflicts:\n");
 
-	strbuf_addf(&(o->commit_msg), "\t%s\n", sha1_to_hex(p->obj));
+	strbuf_addf(&(o->commit_msg), "\t%s\n", oid_to_hex(&p->obj));
 
 	if (o->verbosity >= 2)
-		printf("Auto-merging notes for %s\n", sha1_to_hex(p->obj));
+		printf("Auto-merging notes for %s\n", oid_to_hex(&p->obj));
 	check_notes_merge_worktree(o);
-	if (is_null_sha1(p->local)) {
+	if (is_null_oid(&p->local)) {
 		/* D/F conflict, checkout p->remote */
-		assert(!is_null_sha1(p->remote));
+		assert(!is_null_oid(&p->remote));
 		if (o->verbosity >= 1)
 			printf("CONFLICT (delete/modify): Notes for object %s "
 				"deleted in %s and modified in %s. Version from %s "
 				"left in tree.\n",
-				sha1_to_hex(p->obj), lref, rref, rref);
-		write_note_to_worktree(p->obj, p->remote);
-	} else if (is_null_sha1(p->remote)) {
+				oid_to_hex(&p->obj), lref, rref, rref);
+		write_note_to_worktree(p->obj.hash, p->remote.hash);
+	} else if (is_null_oid(&p->remote)) {
 		/* D/F conflict, checkout p->local */
-		assert(!is_null_sha1(p->local));
+		assert(!is_null_oid(&p->local));
 		if (o->verbosity >= 1)
 			printf("CONFLICT (delete/modify): Notes for object %s "
 				"deleted in %s and modified in %s. Version from %s "
 				"left in tree.\n",
-				sha1_to_hex(p->obj), rref, lref, lref);
-		write_note_to_worktree(p->obj, p->local);
+				oid_to_hex(&p->obj), rref, lref, lref);
+		write_note_to_worktree(p->obj.hash, p->local.hash);
 	} else {
 		/* "regular" conflict, checkout result of ll_merge() */
 		const char *reason = "content";
-		if (is_null_sha1(p->base))
+		if (is_null_oid(&p->base))
 			reason = "add/add";
-		assert(!is_null_sha1(p->local));
-		assert(!is_null_sha1(p->remote));
+		assert(!is_null_oid(&p->local));
+		assert(!is_null_oid(&p->remote));
 		if (o->verbosity >= 1)
 			printf("CONFLICT (%s): Merge conflict in notes for "
-				"object %s\n", reason, sha1_to_hex(p->obj));
+				"object %s\n", reason,
+				oid_to_hex(&p->obj));
 		ll_merge_in_worktree(o, p);
 	}
 
 	trace_printf("\t\t\tremoving from partial merge result\n");
-	remove_note(t, p->obj);
+	remove_note(t, p->obj.hash);
 
 	return 1;
 }
@@ -435,29 +437,29 @@ static int merge_one_change(struct notes_merge_options *o,
 	case NOTES_MERGE_RESOLVE_OURS:
 		if (o->verbosity >= 2)
 			printf("Using local notes for %s\n",
-						sha1_to_hex(p->obj));
+						oid_to_hex(&p->obj));
 		/* nothing to do */
 		return 0;
 	case NOTES_MERGE_RESOLVE_THEIRS:
 		if (o->verbosity >= 2)
 			printf("Using remote notes for %s\n",
-						sha1_to_hex(p->obj));
-		if (add_note(t, p->obj, p->remote, combine_notes_overwrite))
+						oid_to_hex(&p->obj));
+		if (add_note(t, p->obj.hash, p->remote.hash, combine_notes_overwrite))
 			die("BUG: combine_notes_overwrite failed");
 		return 0;
 	case NOTES_MERGE_RESOLVE_UNION:
 		if (o->verbosity >= 2)
 			printf("Concatenating local and remote notes for %s\n",
-							sha1_to_hex(p->obj));
-		if (add_note(t, p->obj, p->remote, combine_notes_concatenate))
+							oid_to_hex(&p->obj));
+		if (add_note(t, p->obj.hash, p->remote.hash, combine_notes_concatenate))
 			die("failed to concatenate notes "
 			    "(combine_notes_concatenate)");
 		return 0;
 	case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
 		if (o->verbosity >= 2)
 			printf("Concatenating unique lines in local and remote "
-				"notes for %s\n", sha1_to_hex(p->obj));
-		if (add_note(t, p->obj, p->remote, combine_notes_cat_sort_uniq))
+				"notes for %s\n", oid_to_hex(&p->obj));
+		if (add_note(t, p->obj.hash, p->remote.hash, combine_notes_cat_sort_uniq))
 			die("failed to concatenate notes "
 			    "(combine_notes_cat_sort_uniq)");
 		return 0;
@@ -475,20 +477,21 @@ static int merge_changes(struct notes_merge_options *o,
 	for (i = 0; i < *num_changes; i++) {
 		struct notes_merge_pair *p = changes + i;
 		trace_printf("\t\t%.7s: %.7s -> %.7s/%.7s\n",
-		       sha1_to_hex(p->obj), sha1_to_hex(p->base),
-		       sha1_to_hex(p->local), sha1_to_hex(p->remote));
+		       oid_to_hex(&p->obj), oid_to_hex(&p->base),
+		       oid_to_hex(&p->local),
+		       oid_to_hex(&p->remote));
 
-		if (!hashcmp(p->base, p->remote)) {
+		if (!oidcmp(&p->base, &p->remote)) {
 			/* no remote change; nothing to do */
 			trace_printf("\t\t\tskipping (no remote change)\n");
-		} else if (!hashcmp(p->local, p->remote)) {
+		} else if (!oidcmp(&p->local, &p->remote)) {
 			/* same change in local and remote; nothing to do */
 			trace_printf("\t\t\tskipping (local == remote)\n");
-		} else if (!hashcmp(p->local, uninitialized) ||
-			   !hashcmp(p->local, p->base)) {
+		} else if (!oidcmp(&p->local, &uninitialized) ||
+			   !oidcmp(&p->local, &p->base)) {
 			/* no local change; adopt remote change */
 			trace_printf("\t\t\tno local change, adopted remote\n");
-			if (add_note(t, p->obj, p->remote,
+			if (add_note(t, p->obj.hash, p->remote.hash,
 				     combine_notes_overwrite))
 				die("BUG: combine_notes_overwrite failed");
 		} else {
diff --git a/notes.c b/notes.c
index df4660f..2bab961 100644
--- a/notes.c
+++ b/notes.c
@@ -993,7 +993,7 @@ const char *default_notes_ref(void)
 void init_notes(struct notes_tree *t, const char *notes_ref,
 		combine_notes_fn combine_notes, int flags)
 {
-	unsigned char sha1[20], object_sha1[20];
+	struct object_id oid, object_oid;
 	unsigned mode;
 	struct leaf_node root_tree;
 
@@ -1017,16 +1017,16 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 	t->dirty = 0;
 
 	if (flags & NOTES_INIT_EMPTY || !notes_ref ||
-	    get_sha1_treeish(notes_ref, object_sha1))
+	    get_sha1_treeish(notes_ref, object_oid.hash))
 		return;
-	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_sha1))
+	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_oid.hash))
 		die("Cannot use notes ref %s", notes_ref);
-	if (get_tree_entry(object_sha1, "", sha1, &mode))
+	if (get_tree_entry(object_oid.hash, "", oid.hash, &mode))
 		die("Failed to read notes tree referenced by %s (%s)",
-		    notes_ref, sha1_to_hex(object_sha1));
+		    notes_ref, oid_to_hex(&object_oid));
 
 	hashclr(root_tree.key_sha1);
-	hashcpy(root_tree.val_sha1, sha1);
+	hashcpy(root_tree.val_sha1, oid.hash);
 	load_subtree(t, &root_tree, t->root, 0);
 }
 
diff --git a/read-cache.c b/read-cache.c
index 491e52d..31eddec 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -161,7 +161,7 @@ static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
 	if (fd >= 0) {
 		unsigned char sha1[20];
 		if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))
-			match = hashcmp(sha1, ce->sha1);
+			match = hashcmp(sha1, ce->oid.hash);
 		/* index_fd() closed the file descriptor already */
 	}
 	return match;
@@ -178,7 +178,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)
 	if (strbuf_readlink(&sb, ce->name, expected_size))
 		return -1;
 
-	buffer = read_sha1_file(ce->sha1, &type, &size);
+	buffer = read_sha1_file(ce->oid.hash, &type, &size);
 	if (buffer) {
 		if (size == sb.len)
 			match = memcmp(buffer, sb.buf, size);
@@ -202,7 +202,7 @@ static int ce_compare_gitlink(const struct cache_entry *ce)
 	 */
 	if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0)
 		return 0;
-	return hashcmp(sha1, ce->sha1);
+	return hashcmp(sha1, ce->oid.hash);
 }
 
 static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st)
@@ -262,7 +262,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
 
 	/* Racily smudged entry? */
 	if (!ce->ce_stat_data.sd_size) {
-		if (!is_empty_blob_sha1(ce->sha1))
+		if (!is_empty_blob_sha1(ce->oid.hash))
 			changed |= DATA_CHANGED;
 	}
 
@@ -624,7 +624,7 @@ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
 	unsigned char sha1[20];
 	if (write_sha1_file("", 0, blob_type, sha1))
 		die("cannot create an empty blob in the object database");
-	hashcpy(ce->sha1, sha1);
+	hashcpy(ce->oid.hash, sha1);
 }
 
 int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags, int force_mode)
@@ -691,7 +691,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 		return 0;
 	}
 	if (!intent_only) {
-		if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT)) {
+		if (index_path(ce->oid.hash, path, st, HASH_WRITE_OBJECT)) {
 			free(ce);
 			return error("unable to index file %s", path);
 		}
@@ -705,7 +705,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 	/* It was suspected to be racily clean, but it turns out to be Ok */
 	was_same = (alias &&
 		    !ce_stage(alias) &&
-		    !hashcmp(alias->sha1, ce->sha1) &&
+		    !oidcmp(&alias->oid, &ce->oid) &&
 		    ce->ce_mode == alias->ce_mode);
 
 	if (pretend)
@@ -744,7 +744,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
 	size = cache_entry_size(len);
 	ce = xcalloc(1, size);
 
-	hashcpy(ce->sha1, sha1);
+	hashcpy(ce->oid.hash, sha1);
 	memcpy(ce->name, path, len);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = len;
@@ -1424,7 +1424,7 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
 	ce->ce_flags = flags & ~CE_NAMEMASK;
 	ce->ce_namelen = len;
 	ce->index = 0;
-	hashcpy(ce->sha1, ondisk->sha1);
+	hashcpy(ce->oid.hash, ondisk->sha1);
 	memcpy(ce->name, name, len);
 	ce->name[len] = '\0';
 	return ce;
@@ -1849,7 +1849,7 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
 	ondisk->uid  = htonl(ce->ce_stat_data.sd_uid);
 	ondisk->gid  = htonl(ce->ce_stat_data.sd_gid);
 	ondisk->size = htonl(ce->ce_stat_data.sd_size);
-	hashcpy(ondisk->sha1, ce->sha1);
+	hashcpy(ondisk->sha1, ce->oid.hash);
 
 	flags = ce->ce_flags & ~CE_NAMEMASK;
 	flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
@@ -2038,7 +2038,7 @@ static int do_write_index(struct index_state *istate, int newfd,
 			continue;
 		if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
 			ce_smudge_racily_clean_entry(ce);
-		if (is_null_sha1(ce->sha1)) {
+		if (is_null_oid(&ce->oid)) {
 			static const char msg[] = "cache entry has null sha1: %s";
 			static int allow = -1;
 
@@ -2285,7 +2285,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un
 	}
 	if (pos < 0)
 		return NULL;
-	data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+	data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz);
 	if (!data || type != OBJ_BLOB) {
 		free(data);
 		return NULL;
diff --git a/refs.c b/refs.c
index 113e3c8..5ffdd77 100644
--- a/refs.c
+++ b/refs.c
@@ -877,6 +877,14 @@ int ref_transaction_verify(struct ref_transaction *transaction,
 				      flags, NULL, err);
 }
 
+int update_ref_oid(const char *msg, const char *refname,
+	       const struct object_id *new_oid, const struct object_id *old_oid,
+	       unsigned int flags, enum action_on_err onerr)
+{
+	return update_ref(msg, refname, new_oid ? new_oid->hash : NULL,
+		old_oid ? old_oid->hash : NULL, flags, onerr);
+}
+
 int update_ref(const char *msg, const char *refname,
 	       const unsigned char *new_sha1, const unsigned char *old_sha1,
 	       unsigned int flags, enum action_on_err onerr)
diff --git a/refs.h b/refs.h
index d42458c..fe51280 100644
--- a/refs.h
+++ b/refs.h
@@ -480,6 +480,9 @@ void ref_transaction_free(struct ref_transaction *transaction);
 int update_ref(const char *msg, const char *refname,
 	       const unsigned char *new_sha1, const unsigned char *old_sha1,
 	       unsigned int flags, enum action_on_err onerr);
+int update_ref_oid(const char *msg, const char *refname,
+	       const struct object_id *new_oid, const struct object_id *old_oid,
+	       unsigned int flags, enum action_on_err onerr);
 
 int parse_hide_refs_config(const char *var, const char *value, const char *);
 
diff --git a/rerere.c b/rerere.c
index aaadec1..5d083ca 100644
--- a/rerere.c
+++ b/rerere.c
@@ -980,7 +980,8 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
 			break;
 		i = ce_stage(ce) - 1;
 		if (!mmfile[i].ptr) {
-			mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size);
+			mmfile[i].ptr = read_sha1_file(ce->oid.hash, &type,
+						       &size);
 			mmfile[i].size = size;
 		}
 	}
diff --git a/resolve-undo.c b/resolve-undo.c
index 468a2eb..b40f317 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -24,7 +24,7 @@ void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
 	if (!lost->util)
 		lost->util = xcalloc(1, sizeof(*ui));
 	ui = lost->util;
-	hashcpy(ui->sha1[stage - 1], ce->sha1);
+	hashcpy(ui->sha1[stage - 1], ce->oid.hash);
 	ui->mode[stage - 1] = ce->ce_mode;
 }
 
diff --git a/revision.c b/revision.c
index 8a29cb0..969b3d1 100644
--- a/revision.c
+++ b/revision.c
@@ -1275,7 +1275,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)
 		if (S_ISGITLINK(ce->ce_mode))
 			continue;
 
-		blob = lookup_blob(ce->sha1);
+		blob = lookup_blob(ce->oid.hash);
 		if (!blob)
 			die("unable to add index blob to traversal");
 		add_pending_object_with_path(revs, &blob->object, "",
diff --git a/sha1_name.c b/sha1_name.c
index ca7ddd6..faf873c 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -995,35 +995,35 @@ static int interpret_nth_prior_checkout(const char *name, int namelen,
 	return retval;
 }
 
-int get_sha1_mb(const char *name, unsigned char *sha1)
+int get_oid_mb(const char *name, struct object_id *oid)
 {
 	struct commit *one, *two;
 	struct commit_list *mbs;
-	unsigned char sha1_tmp[20];
+	struct object_id oid_tmp;
 	const char *dots;
 	int st;
 
 	dots = strstr(name, "...");
 	if (!dots)
-		return get_sha1(name, sha1);
+		return get_oid(name, oid);
 	if (dots == name)
-		st = get_sha1("HEAD", sha1_tmp);
+		st = get_oid("HEAD", &oid_tmp);
 	else {
 		struct strbuf sb;
 		strbuf_init(&sb, dots - name);
 		strbuf_add(&sb, name, dots - name);
-		st = get_sha1_committish(sb.buf, sha1_tmp);
+		st = get_sha1_committish(sb.buf, oid_tmp.hash);
 		strbuf_release(&sb);
 	}
 	if (st)
 		return st;
-	one = lookup_commit_reference_gently(sha1_tmp, 0);
+	one = lookup_commit_reference_gently(oid_tmp.hash, 0);
 	if (!one)
 		return -1;
 
-	if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", sha1_tmp))
+	if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
 		return -1;
-	two = lookup_commit_reference_gently(sha1_tmp, 0);
+	two = lookup_commit_reference_gently(oid_tmp.hash, 0);
 	if (!two)
 		return -1;
 	mbs = get_merge_bases(one, two);
@@ -1031,7 +1031,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
 		st = -1;
 	else {
 		st = 0;
-		hashcpy(sha1, mbs->item->object.oid.hash);
+		oidcpy(oid, &mbs->item->object.oid);
 	}
 	free_commit_list(mbs);
 	return st;
@@ -1435,7 +1435,7 @@ static int get_sha1_with_context_1(const char *name,
 			    memcmp(ce->name, cp, namelen))
 				break;
 			if (ce_stage(ce) == stage) {
-				hashcpy(sha1, ce->sha1);
+				hashcpy(sha1, ce->oid.hash);
 				oc->mode = ce->ce_mode;
 				free(new_path);
 				return 0;
diff --git a/streaming.c b/streaming.c
index 811fcc2..3c48f04 100644
--- a/streaming.c
+++ b/streaming.c
@@ -497,7 +497,7 @@ static open_method_decl(incore)
  * Users of streaming interface
  ****************************************************************/
 
-int stream_blob_to_fd(int fd, unsigned const char *sha1, struct stream_filter *filter,
+int stream_blob_to_fd(int fd, const struct object_id *oid, struct stream_filter *filter,
 		      int can_seek)
 {
 	struct git_istream *st;
@@ -506,7 +506,7 @@ int stream_blob_to_fd(int fd, unsigned const char *sha1, struct stream_filter *f
 	ssize_t kept = 0;
 	int result = -1;
 
-	st = open_istream(sha1, &type, &sz, filter);
+	st = open_istream(oid->hash, &type, &sz, filter);
 	if (!st) {
 		if (filter)
 			free_stream_filter(filter);
diff --git a/streaming.h b/streaming.h
index 1d05c2a..73c1d15 100644
--- a/streaming.h
+++ b/streaming.h
@@ -12,6 +12,6 @@ extern struct git_istream *open_istream(const unsigned char *, enum object_type
 extern int close_istream(struct git_istream *);
 extern ssize_t read_istream(struct git_istream *, void *, size_t);
 
-extern int stream_blob_to_fd(int fd, const unsigned char *, struct stream_filter *, int can_seek);
+extern int stream_blob_to_fd(int fd, const struct object_id *, struct stream_filter *, int can_seek);
 
 #endif /* STREAMING_H */
diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c
index d168924..e44430b 100644
--- a/t/helper/test-dump-split-index.c
+++ b/t/helper/test-dump-split-index.c
@@ -23,7 +23,7 @@ int cmd_main(int ac, const char **av)
 	for (i = 0; i < the_index.cache_nr; i++) {
 		struct cache_entry *ce = the_index.cache[i];
 		printf("%06o %s %d\t%s\n", ce->ce_mode,
-		       sha1_to_hex(ce->sha1), ce_stage(ce), ce->name);
+		       oid_to_hex(&ce->oid), ce_stage(ce), ce->name);
 	}
 	printf("replacements:");
 	if (si->replace_bitmap)
diff --git a/tree.c b/tree.c
index 0089e52..2b5a5a8 100644
--- a/tree.c
+++ b/tree.c
@@ -26,7 +26,7 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
 	ce->ce_namelen = baselen + len;
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
-	hashcpy(ce->sha1, sha1);
+	hashcpy(ce->oid.hash, sha1);
 	return add_cache_entry(ce, opt);
 }
 
diff --git a/unpack-trees.c b/unpack-trees.c
index c87a90a..8851691 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -625,7 +625,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
 	ce->ce_mode = create_ce_mode(n->mode);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = len;
-	hashcpy(ce->sha1, n->oid->hash);
+	oidcpy(&ce->oid, n->oid);
 	make_traverse_path(ce->name, info, n);
 
 	return ce;
@@ -1287,7 +1287,7 @@ static int same(const struct cache_entry *a, const struct cache_entry *b)
 	if ((a->ce_flags | b->ce_flags) & CE_CONFLICTED)
 		return 0;
 	return a->ce_mode == b->ce_mode &&
-	       !hashcmp(a->sha1, b->sha1);
+	       !oidcmp(&a->oid, &b->oid);
 }
 
 
@@ -1393,7 +1393,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
 		/* If we are not going to update the submodule, then
 		 * we don't care.
 		 */
-		if (!hashcmp(sha1, ce->sha1))
+		if (!hashcmp(sha1, ce->oid.hash))
 			return 0;
 		return verify_clean_submodule(ce, error_type, o);
 	}
@@ -1665,7 +1665,7 @@ static void show_stage_entry(FILE *o,
 		fprintf(o, "%s%06o %s %d\t%s\n",
 			label,
 			ce->ce_mode,
-			sha1_to_hex(ce->sha1),
+			oid_to_hex(&ce->oid),
 			ce_stage(ce),
 			ce->name);
 }
diff --git a/wt-status.c b/wt-status.c
index 539aac1..9a14658 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -623,7 +623,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
 			d->index_status = DIFF_STATUS_ADDED;
 			/* Leave {mode,oid}_head zero for adds. */
 			d->mode_index = ce->ce_mode;
-			hashcpy(d->oid_index.hash, ce->sha1);
+			hashcpy(d->oid_index.hash, ce->oid.hash);
 		}
 	}
 }
@@ -2093,7 +2093,7 @@ static void wt_porcelain_v2_print_unmerged_entry(
 		if (strcmp(ce->name, it->string) || !stage)
 			break;
 		stages[stage - 1].mode = ce->ce_mode;
-		hashcpy(stages[stage - 1].oid.hash, ce->sha1);
+		hashcpy(stages[stage - 1].oid.hash, ce->oid.hash);
 		sum |= (1 << (stage - 1));
 	}
 	if (sum != d->stagemask)
diff --git a/xdiff-interface.c b/xdiff-interface.c
index f34ea76..3bfc69c 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -178,20 +178,20 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
 	return 0;
 }
 
-void read_mmblob(mmfile_t *ptr, const unsigned char *sha1)
+void read_mmblob(mmfile_t *ptr, const struct object_id *oid)
 {
 	unsigned long size;
 	enum object_type type;
 
-	if (!hashcmp(sha1, null_sha1)) {
+	if (!oidcmp(oid, &null_oid)) {
 		ptr->ptr = xstrdup("");
 		ptr->size = 0;
 		return;
 	}
 
-	ptr->ptr = read_sha1_file(sha1, &type, &size);
+	ptr->ptr = read_sha1_file(oid->hash, &type, &size);
 	if (!ptr->ptr || type != OBJ_BLOB)
-		die("unable to read blob object %s", sha1_to_hex(sha1));
+		die("unable to read blob object %s", oid_to_hex(oid));
 	ptr->size = size;
 }
 
diff --git a/xdiff-interface.h b/xdiff-interface.h
index fbb5a1c..6f6ba90 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -1,6 +1,7 @@
 #ifndef XDIFF_INTERFACE_H
 #define XDIFF_INTERFACE_H
 
+#include "cache.h"
 #include "xdiff/xdiff.h"
 
 /*
@@ -20,7 +21,7 @@ int parse_hunk_header(char *line, int len,
 		      int *ob, int *on,
 		      int *nb, int *nn);
 int read_mmfile(mmfile_t *ptr, const char *filename);
-void read_mmblob(mmfile_t *ptr, const unsigned char *sha1);
+void read_mmblob(mmfile_t *ptr, const struct object_id *oid);
 int buffer_is_binary(const char *ptr, unsigned long size);
 
 extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);