diff options
author | Johannes Schindelin <Johannes.Schindelin@gmx.de> | 2007-02-24 03:08:20 +0100 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2007-02-24 02:06:18 -0800 |
commit | 28a4d940443806412effa246ecc7768a21553ec7 (patch) | |
tree | 8fc59a1c97cfd8df66791004c040366ec3b78675 /sha1_name.c | |
parent | 7bd59dee5b4b42f2ed233141e33713a7f012dd22 (diff) | |
download | git-28a4d940443806412effa246ecc7768a21553ec7.tar.gz git-28a4d940443806412effa246ecc7768a21553ec7.tar.xz |
object name: introduce ':/<oneline prefix>' notation
To name a commit, you can now say
$ git rev-parse ':/Initial revision of "git"'
and it will return the hash of the youngest commit whose
commit message (the oneline) begins with the given prefix.
For future extension, a leading exclamation mark is treated
specially: if you want to match a commit message starting with
a '!', just repeat the exclamation mark. So, to match a commit
which starts with '!Hello World', use
$ git show ':/!!Hello World'
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'sha1_name.c')
-rw-r--r-- | sha1_name.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/sha1_name.c b/sha1_name.c index a7efa96f3..0781477a7 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]) |