X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=sha1_name.c;h=267ea3f3edc63600bc1591d2115ee85222f3e8c5;hb=7da3bf372cfcd25ea44164afb90c306836b62e23;hp=a7efa96f35c3a9aadf222f934c37515f00e68676;hpb=460ca302fdf453459850676c049ed7b46b43a0d4;p=git.git diff --git a/sha1_name.c b/sha1_name.c index a7efa96f3..267ea3f3e 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -71,19 +71,19 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char * static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) { struct packed_git *p; - unsigned char found_sha1[20]; + const unsigned char *found_sha1 = NULL; int found = 0; prepare_packed_git(); for (p = packed_git; p && found < 2; p = p->next) { - unsigned num = num_packed_objects(p); - unsigned first = 0, last = num; + uint32_t num = num_packed_objects(p); + uint32_t first = 0, last = num; while (first < last) { - unsigned mid = (first + last) / 2; - unsigned char now[20]; + uint32_t mid = (first + last) / 2; + const unsigned char *now; int cmp; - nth_packed_object_sha1(p, mid, now); + now = nth_packed_object_sha1(p, mid); cmp = hashcmp(match, now); if (!cmp) { first = mid; @@ -96,14 +96,14 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne last = mid; } if (first < num) { - unsigned char now[20], next[20]; - nth_packed_object_sha1(p, first, now); + const unsigned char *now, *next; + now = nth_packed_object_sha1(p, first); if (match_sha(len, match, now)) { - if (nth_packed_object_sha1(p, first+1, next) || - !match_sha(len, match, next)) { + next = nth_packed_object_sha1(p, first+1); + if (!next|| !match_sha(len, match, next)) { /* unique within this pack */ if (!found) { - hashcpy(found_sha1, now); + found_sha1 = now; found++; } else if (hashcmp(found_sha1, now)) { @@ -577,6 +577,66 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1) return get_short_sha1(name, len, sha1, 0); } +static int handle_one_ref(const char *path, + const unsigned char *sha1, int flag, void *cb_data) +{ + struct commit_list **list = cb_data; + struct object *object = parse_object(sha1); + if (!object) + return 0; + if (object->type == OBJ_TAG) + object = deref_tag(object, path, strlen(path)); + if (object->type != OBJ_COMMIT) + return 0; + insert_by_date((struct commit *)object, list); + return 0; +} + +/* + * This interprets names like ':/Initial revision of "git"' by searching + * through history and returning the first commit whose message starts + * with the given string. + * + * For future extension, ':/!' is reserved. If you want to match a message + * beginning with a '!', you have to repeat the exclamation mark. + */ + +#define ONELINE_SEEN (1u<<20) +static int get_sha1_oneline(const char *prefix, unsigned char *sha1) +{ + struct commit_list *list = NULL, *backup = NULL, *l; + int retval = -1; + + if (prefix[0] == '!') { + if (prefix[1] != '!') + die ("Invalid search pattern: %s", prefix); + prefix++; + } + if (!save_commit_buffer) + return error("Could not expand oneline-name."); + for_each_ref(handle_one_ref, &list); + for (l = list; l; l = l->next) + commit_list_insert(l->item, &backup); + while (list) { + char *p; + struct commit *commit; + + commit = pop_most_recent_commit(&list, ONELINE_SEEN); + parse_object(commit->object.sha1); + if (!commit->buffer || !(p = strstr(commit->buffer, "\n\n"))) + continue; + if (!prefixcmp(p + 2, prefix)) { + hashcpy(sha1, commit->object.sha1); + retval = 0; + break; + } + } + free_commit_list(list); + for (l = backup; l; l = l->next) + clear_commit_marks(l->item, ONELINE_SEEN); + return retval; +} + /* * This is like "get_sha1_basic()", except it allows "sha1 expressions", * notably "xyz^" for "parent of xyz" @@ -600,6 +660,8 @@ int get_sha1(const char *name, unsigned char *sha1) int stage = 0; struct cache_entry *ce; int pos; + if (namelen > 2 && name[1] == '/') + return get_sha1_oneline(name + 2, sha1); if (namelen < 3 || name[2] != ':' || name[1] < '0' || '3' < name[1])