diff options
author | Junio C Hamano <junkio@cox.net> | 2007-02-28 14:56:08 -0800 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2007-02-28 14:56:08 -0800 |
commit | 16d53152f10bf5c1cae4eb1f85dfab7dc280f913 (patch) | |
tree | 4415d41abf54e98e282b53b5445b9376bbaab928 | |
parent | Merge branch 'js/bundle' (diff) | |
parent | object name: introduce ':/<oneline prefix>' notation (diff) | |
download | tgif-16d53152f10bf5c1cae4eb1f85dfab7dc280f913.tar.xz |
Merge branch 'js/commit-by-name'
* js/commit-by-name:
object name: introduce ':/<oneline prefix>' notation
-rw-r--r-- | Documentation/git-rev-parse.txt | 7 | ||||
-rw-r--r-- | sha1_name.c | 58 |
2 files changed, 65 insertions, 0 deletions
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 4041a16070..ccc66aae7f 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -190,6 +190,13 @@ blobs contained in a commit. and dereference the tag recursively until a non-tag object is found. +* A colon, followed by a slash, followed by a text: this names + a commit whose commit message starts with the specified text. + This name returns the youngest matching commit which is + reachable from any ref. If the commit message starts with a + '!', you have to repeat that; the special sequence ':/!', + followed by something else than '!' is reserved for now. + * A suffix ':' followed by a path; this names the blob or tree at the given path in the tree-ish object named by the part before the colon. diff --git a/sha1_name.c b/sha1_name.c index a7efa96f35..0781477a71 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -577,6 +577,62 @@ 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) +int get_sha1_oneline(const char *prefix, unsigned char *sha1) +{ + struct commit_list *list = NULL, *backup = NULL, *l; + struct commit *commit; + + 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 ((commit = pop_most_recent_commit(&list, ONELINE_SEEN))) { + char *p; + 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); + break; + } + } + free_commit_list(list); + for (l = backup; l; l = l->next) + clear_commit_marks(l->item, ONELINE_SEEN); + return commit == NULL; +} + /* * This is like "get_sha1_basic()", except it allows "sha1 expressions", * notably "xyz^" for "parent of xyz" @@ -600,6 +656,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]) |