To name a commit, you can now say git rev-parse ':::Initial revision of "git"' and it will return the hash of the first youngest commit whose commit message (the oneline) begins with the given prefix. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- I often do "git log --grep=bla" to find a certain commit, then grab my mouse, mark the commit hash, and paste it into the command line I really want to run on that commit. This allows me to throw away my mouse. sha1_name.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 50 insertions(+), 0 deletions(-) diff --git a/sha1_name.c b/sha1_name.c index 2793de9..004c4e3 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -578,6 +578,54 @@ 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. + */ + +#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 (!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" @@ -601,6 +649,8 @@ int get_sha1(const char *name, unsigned char *sha1) int stage = 0; struct cache_entry *ce = NULL; int pos; + if (namelen > 3 && !prefixcmp(name + 1, "::")) + return get_sha1_oneline(name + 3, sha1); if (namelen < 3 || name[2] != ':' || name[1] < '0' || '3' < name[1]) -- 1.5.0.1.2246.geaab8-dirty - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html