Store peeled refs in packed-refs file.
This would speed up "show-ref -d" in a repository with mostly packed tags. Signed-off-by: Junio C Hamano <junkio@cox.net>maint
							parent
							
								
									ef06b91804
								
							
						
					
					
						commit
						cf0adba788
					
				|  | @ -1,5 +1,7 @@ | |||
| #include "cache.h" | ||||
| #include "refs.h" | ||||
| #include "object.h" | ||||
| #include "tag.h" | ||||
|  | ||||
| static const char builtin_pack_refs_usage[] = | ||||
| "git-pack-refs [--all] [--prune]"; | ||||
|  | @ -29,12 +31,26 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, | |||
| 			  int flags, void *cb_data) | ||||
| { | ||||
| 	struct pack_refs_cb_data *cb = cb_data; | ||||
| 	int is_tag_ref; | ||||
|  | ||||
| 	if (!cb->all && strncmp(path, "refs/tags/", 10)) | ||||
| 		return 0; | ||||
| 	/* Do not pack the symbolic refs */ | ||||
| 	if (!(flags & REF_ISSYMREF)) | ||||
| 		fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path); | ||||
| 	if ((flags & REF_ISSYMREF)) | ||||
| 		return 0; | ||||
| 	is_tag_ref = !strncmp(path, "refs/tags/", 10); | ||||
| 	if (!cb->all && !is_tag_ref) | ||||
| 		return 0; | ||||
|  | ||||
| 	fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path); | ||||
| 	if (is_tag_ref) { | ||||
| 		struct object *o = parse_object(sha1); | ||||
| 		if (o->type == OBJ_TAG) { | ||||
| 			o = deref_tag(o, path, 0); | ||||
| 			if (o) | ||||
| 				fprintf(cb->refs_file, "%s  %s^{}\n", | ||||
| 					sha1_to_hex(o->sha1), path); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (cb->prune && !do_not_prune(flags)) { | ||||
| 		int namelen = strlen(path) + 1; | ||||
| 		struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen); | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo | |||
| { | ||||
| 	struct object *obj; | ||||
| 	const char *hex; | ||||
| 	unsigned char peeled[20]; | ||||
|  | ||||
| 	if (tags_only || heads_only) { | ||||
| 		int match; | ||||
|  | @ -44,12 +45,15 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo | |||
|  | ||||
| match: | ||||
| 	found_match++; | ||||
| 	obj = parse_object(sha1); | ||||
| 	if (!obj) { | ||||
| 		if (quiet) | ||||
| 			return 0; | ||||
| 		die("git-show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1)); | ||||
| 	} | ||||
|  | ||||
| 	/* This changes the semantics slightly that even under quiet we | ||||
| 	 * detect and return error if the repository is corrupt and | ||||
| 	 * ref points at a nonexistent object. | ||||
| 	 */ | ||||
| 	if (!has_sha1_file(sha1)) | ||||
| 		die("git-show-ref: bad ref %s (%s)", refname, | ||||
| 		    sha1_to_hex(sha1)); | ||||
|  | ||||
| 	if (quiet) | ||||
| 		return 0; | ||||
|  | ||||
|  | @ -58,11 +62,25 @@ match: | |||
| 		printf("%s\n", hex); | ||||
| 	else | ||||
| 		printf("%s %s\n", hex, refname); | ||||
| 	if (deref_tags && obj->type == OBJ_TAG) { | ||||
| 		obj = deref_tag(obj, refname, 0); | ||||
| 		hex = find_unique_abbrev(obj->sha1, abbrev); | ||||
|  | ||||
| 	if (!deref_tags) | ||||
| 		return 0; | ||||
|  | ||||
| 	if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) { | ||||
| 		hex = find_unique_abbrev(peeled, abbrev); | ||||
| 		printf("%s %s^{}\n", hex, refname); | ||||
| 	} | ||||
| 	else { | ||||
| 		obj = parse_object(sha1); | ||||
| 		if (!obj) | ||||
| 			die("git-show-ref: bad ref %s (%s)", refname, | ||||
| 			    sha1_to_hex(sha1)); | ||||
| 		if (obj->type == OBJ_TAG) { | ||||
| 			obj = deref_tag(obj, refname, 0); | ||||
| 			hex = find_unique_abbrev(obj->sha1, abbrev); | ||||
| 			printf("%s %s^{}\n", hex, refname); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  |  | |||
							
								
								
									
										73
									
								
								refs.c
								
								
								
								
							
							
						
						
									
										73
									
								
								refs.c
								
								
								
								
							|  | @ -1,16 +1,18 @@ | |||
| #include "refs.h" | ||||
| #include "cache.h" | ||||
| #include "object.h" | ||||
| #include "tag.h" | ||||
|  | ||||
| #include <errno.h> | ||||
|  | ||||
| struct ref_list { | ||||
| 	struct ref_list *next; | ||||
| 	unsigned char flag; /* ISSYMREF? ISPACKED? */ | ||||
| 	unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */ | ||||
| 	unsigned char sha1[20]; | ||||
| 	char name[FLEX_ARRAY]; | ||||
| }; | ||||
|  | ||||
| static const char *parse_ref_line(char *line, unsigned char *sha1) | ||||
| static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag) | ||||
| { | ||||
| 	/* | ||||
| 	 * 42: the answer to everything. | ||||
|  | @ -21,6 +23,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1) | |||
| 	 *  +1 (newline at the end of the line) | ||||
| 	 */ | ||||
| 	int len = strlen(line) - 42; | ||||
| 	int peeled = 0; | ||||
|  | ||||
| 	if (len <= 0) | ||||
| 		return NULL; | ||||
|  | @ -29,11 +32,24 @@ static const char *parse_ref_line(char *line, unsigned char *sha1) | |||
| 	if (!isspace(line[40])) | ||||
| 		return NULL; | ||||
| 	line += 41; | ||||
| 	if (isspace(*line)) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (isspace(*line)) { | ||||
| 		/* "SHA-1 SP SP refs/tags/tagname^{} LF"? */ | ||||
| 		line++; | ||||
| 		len--; | ||||
| 		peeled = 1; | ||||
| 	} | ||||
| 	if (line[len] != '\n') | ||||
| 		return NULL; | ||||
| 	line[len] = 0; | ||||
|  | ||||
| 	if (peeled && (len < 3 || strcmp(line + len - 3, "^{}"))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (!peeled) | ||||
| 		*flag &= ~REF_ISPEELED; | ||||
| 	else | ||||
| 		*flag |= REF_ISPEELED; | ||||
| 	return line; | ||||
| } | ||||
|  | ||||
|  | @ -108,10 +124,12 @@ static struct ref_list *get_packed_refs(void) | |||
| 			char refline[PATH_MAX]; | ||||
| 			while (fgets(refline, sizeof(refline), f)) { | ||||
| 				unsigned char sha1[20]; | ||||
| 				const char *name = parse_ref_line(refline, sha1); | ||||
| 				int flag = REF_ISPACKED; | ||||
| 				const char *name = | ||||
| 					parse_ref_line(refline, sha1, &flag); | ||||
| 				if (!name) | ||||
| 					continue; | ||||
| 				list = add_ref(name, sha1, REF_ISPACKED, list); | ||||
| 				list = add_ref(name, sha1, flag, list); | ||||
| 			} | ||||
| 			fclose(f); | ||||
| 			refs = list; | ||||
|  | @ -207,7 +225,8 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int * | |||
| 		if (lstat(path, &st) < 0) { | ||||
| 			struct ref_list *list = get_packed_refs(); | ||||
| 			while (list) { | ||||
| 				if (!strcmp(ref, list->name)) { | ||||
| 				if (!(list->flag & REF_ISPEELED) && | ||||
| 				    !strcmp(ref, list->name)) { | ||||
| 					hashcpy(sha1, list->sha1); | ||||
| 					if (flag) | ||||
| 						*flag |= REF_ISPACKED; | ||||
|  | @ -329,6 +348,8 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, | |||
| 		return 0; | ||||
| 	if (is_null_sha1(entry->sha1)) | ||||
| 		return 0; | ||||
| 	if (entry->flag & REF_ISPEELED) | ||||
| 		return 0; | ||||
| 	if (!has_sha1_file(entry->sha1)) { | ||||
| 		error("%s does not point to a valid object!", entry->name); | ||||
| 		return 0; | ||||
|  | @ -336,6 +357,44 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, | |||
| 	return fn(entry->name + trim, entry->sha1, entry->flag, cb_data); | ||||
| } | ||||
|  | ||||
| int peel_ref(const char *ref, unsigned char *sha1) | ||||
| { | ||||
| 	int flag; | ||||
| 	unsigned char base[20]; | ||||
| 	struct object *o; | ||||
|  | ||||
| 	if (!resolve_ref(ref, base, 1, &flag)) | ||||
| 		return -1; | ||||
|  | ||||
| 	if ((flag & REF_ISPACKED)) { | ||||
| 		struct ref_list *list = get_packed_refs(); | ||||
| 		int len = strlen(ref); | ||||
|  | ||||
| 		while (list) { | ||||
| 			if ((list->flag & REF_ISPEELED) && | ||||
| 			    !strncmp(list->name, ref, len) && | ||||
| 			    strlen(list->name) == len + 3 && | ||||
| 			    !strcmp(list->name + len, "^{}")) { | ||||
| 				hashcpy(sha1, list->sha1); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			list = list->next; | ||||
| 		} | ||||
| 		/* older pack-refs did not leave peeled ones in */ | ||||
| 	} | ||||
|  | ||||
| 	/* otherwise ... */ | ||||
| 	o = parse_object(base); | ||||
| 	if (o->type == OBJ_TAG) { | ||||
| 		o = deref_tag(o, ref, 0); | ||||
| 		if (o) { | ||||
| 			hashcpy(sha1, o->sha1); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, | ||||
| 			   void *cb_data) | ||||
| { | ||||
|  |  | |||
							
								
								
									
										4
									
								
								refs.h
								
								
								
								
							
							
						
						
									
										4
									
								
								refs.h
								
								
								
								
							|  | @ -16,6 +16,8 @@ struct ref_lock { | |||
|  */ | ||||
| #define REF_ISSYMREF 01 | ||||
| #define REF_ISPACKED 02 | ||||
| #define REF_ISPEELED 04 /* internal use */ | ||||
|  | ||||
| typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data); | ||||
| extern int head_ref(each_ref_fn, void *); | ||||
| extern int for_each_ref(each_ref_fn, void *); | ||||
|  | @ -23,6 +25,8 @@ extern int for_each_tag_ref(each_ref_fn, void *); | |||
| extern int for_each_branch_ref(each_ref_fn, void *); | ||||
| extern int for_each_remote_ref(each_ref_fn, void *); | ||||
|  | ||||
| extern int peel_ref(const char *, unsigned char *); | ||||
|  | ||||
| /** Reads the refs file specified into sha1 **/ | ||||
| extern int get_ref_sha1(const char *ref, unsigned char *sha1); | ||||
|  | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano